I want to listen for keypresses and depending on those, use commands from System.Console.ANSI
package to manipulate console interface for my program.
In Python I would to this
while True:
read_from_console()
if condition:
print_stuff_into_console
break
How do I approach such task in Haskell, in simplest possible way?
Thanks
The equivalent abstract pseudo-ish code in Haskell would look like:
loop = do
line <- readFromConsole
if condition line
then do
printStuffToConsole
loop -- Recurse - i.e. repeat the same thing again
else
pure () -- Don't recurse - the function execution ends
main = loop
But of course the devil would be in how readFromConsole and printStuffToConsole look. And these really depend on what exactly you'd like to do.
I will offer the dumbest possible implementation, just to illustrate how everything works and to build a complete program.
Let's say that "read from console" just means having the user enter a line of text and press Enter. For that, you can use the getLine function:
readFromConsole = getLine
And let's say you want to print the same thing every time. For printing, you can use the putStrLn function:
printStuffToConsole = putStrLn "Give me another!"
And then let's say that the condition for stopping is that the user enters "STOP". This can be expressed with a string comparison:
condition line = line /= "STOP"
If you put all of that together, you get a complete program:
loop = do
line <- readFromConsole
if condition line
then do
printStuffToConsole
loop -- Recurse - i.e. repeat the same thing again
else
pure () -- Don't recurse - the function execution ends
where
readFromConsole = getLine
printStuffToConsole = putStrLn "Give me another!"
condition line = line /= "STOP"
main = loop
Of course, while it's nice to have parts of the program semantically named, you don't strictly speaking have to do it if you wanted to make the whole thing shorter:
main = do
line <- getLine
if line /= "STOP"
then do
putStrLn "Give me another!"
main
else
pure ()
Fyodor Soikin already provided the simple way to do it.
Here I'll comment on a general way to "break" a loop: using continuations and callCC.
import Control.Monad.Cont
main :: IO ()
main = do
putStrLn "start"
flip runContT return $ callCC $ \break -> forever $ do
l <- lift $ getLine
if l == "quit"
then break ()
else lift $ putStrLn $ "not a quit command " ++ l
lift $ putStrLn "next iteration"
putStrLn "end"
Continuations are infamously hard to grasp, but the above code is not too complex. A rough intuition is as follows.
The forever library function is used to repeat an action indefinitely, it is the Haskell equivalent of while true.
The flip runContT return $ callCC $ \f -> .... part means "define f to be a break-like function, which will exit the "block" .... immediately. In the code, I call that break to make that clear. The call break () interrupts the forever (and returns the () outside -- we could use that value if we wrote x <- flip runContT .... to bind it to x).
There is a downside, though. In the .... part we no longer work inside the IO monad, but in the ContT () IO monad. That is what lets us call break (). In order to use regular IO there, we need to lift the IO actions. So, we can't use putStrLn ".." but we need to use lift $ putStrLn ".." instead.
The rest should be more or less straightforward to follow.
Here's a small demo in GHCi.
> main
start
1 (typed by the user)
not a quit command 1
next iteration
2 (typed by the user)
not a quit command 2
next iteration
3 (typed by the user)
not a quit command 3
next iteration
4 (typed by the user)
not a quit command 4
next iteration
quit (typed by the user)
end
Is it a good idea to use continuation just for break? Maybe. If you are not familiar with this technique, probably it is not worth it. The plain recursive approach looks much simpler.
Related
I am basically making a task manager where a user can add a task or print out all tasks entered.
my main function contains the options of what users do...
main = do
putStrLn "Below are the Options:\n\tadd\n\tprint\n\tsearch\nEnter Option:"
input <- getLine
if input == "add" then
buildList []
else if input == "print" then
putStrLn "printing"
else if input == "search" then
putStrLn "searching"
else
putStrLn "Please Enter add, print, search"
main
I am working on a function called buildList where the creation of the task happens:
buildList tasks = do
putStrLn "Enter a Task:"
input <- getLine
let mytask = input
putStrLn mytask --here to prevent an error
..and I assume I would need a global list since I will need it if I want to print out or search within it.
mytasklist = []
I have been stuck on this for a while as I am new to functional programming and Haskell. I understand that I can add two list together with ++ or just do : to add at the start of the list, but I cant seem to figure out how to achieve this without an error.
update1: so would something like this work?
buildList tasks = do
putStrLn "Enter a Task:"
input <- getLine
let updatedTasks = tasks ++ [input]
main
main = do
putStrLn "Below are the Options:\n\tadd\n\tprint\n\tsearch\nEnter Option:"
input <- getLine
if input == "add" then do
buildList []
else if input == "print" then
putStrLn "searchiwng"
else if input == "search" then
putStrLn "searching"
else
putStrLn "Please Enter add, print, search"
main
You need to rename your main function to something else, lets say go (seems to be the traditional name for this pattern) and pass your task list as a parameter to go. In the case of "add" the list you pass is the old list plus the new entry.
(Obviously this is a toy problem for learning, and this is a toy solution. Real programs have more sophisticated approaches. But this will do for now).
Here is a simpler example, where you can increase or print an integer.
You could try to adapt it to your task.
The trick is the recursive function loop, which calls itself with the updated integer.
main :: IO ()
main = do
let loop :: Int -> IO ()
loop n = do
putStrLn "print/inc/quit?"
opt <- getLine
case opt of
"print" -> do print n; loop n -- recurse with the same n
"inc" -> loop (n+1) -- recurse with updated n
"quit" -> putStrLn "bye!" -- don't recurse to stop
_ -> do putStrLn "invalid option, try again"; loop n
-- call loop prividing the intial value
loop 0
You can also make loop into a top-level function, and simply define main = loop 0, if you prefer.
There are, of course, several other more advanced options in Haskell to do this, but I'd recommend you start with the above basic approach.
When you are more familiar with the language, you could try the following alternative options:
the StateT Int IO monad allows IO operations and reading/writing to an Int state
IORefs can also be used to model mutable data
In contrast to the information in "learn you a haskell", on my windows system, ghci translates CTRL-D to EOT, not EOF.
Thus, when I do something like:
input <- getContents
doSomething input
, where doSomething is a function which consumes the input.
Doing that, I have to press CTRL-Z to end my input text, which makes sense since getContents is intended for process piping...
But if I repeat the above steps a second time, it fails because stdin is closed.
So, while browsing System.IO, I could not find an alternative to getContents, which would react on EOT.
Do I have to write such a function myself or is it to be found in another package, maybe?
Btw, the version of GHCI, I use is 8.2.2.
Also, I do not want single line processing. I am aware of getLine but it is not what I want in this case.
Here is the function I was looking for:
getContentsEOT :: IO String
getContentsEOT =
getChar >>= \c ->
if c == '\EOT'
then return ""
else getContentsEOT >>= \s ->
return (c:s)
Haskell IO is often explained in terms of the entire program being a pure function (main) that returns an IO value (often described as an imperative IO program), which is then executed by the runtime.
This mental model works fine for simple examples, but fell over for me as soon as I saw a recursive main in Learn You A Haskell. For example:
main = do
line <- getLine
putStrLn line
main
Or, if you prefer:
main = getLine >>= putStrLn >> main
Since main never terminates, it never actually returns an IO value, yet the program endlessly reads and echoes back lines just fine - so the simple explanation above doesn't quite work. Am I missing something simple or is there a more complete explanation (or is it 'simply' compiler magic) ?
In this case, main is a value of type IO () rather than a function. You can think of it as a sequence of IO a values:
main = getLine >>= putStrLn >> main
This makes it a recursive value, not unlike infinite lists:
foo = 1 : 2 : foo
We can return a value like this without needing to evaluate the whole thing. In fact, it's a reasonably common idiom.
foo will loop forever if you try to use the whole thing. But that's true of main too: unless you use some external method to break out of it, it will never stop looping! But you can start getting elements out of foo, or executing parts of main, without evaluating all of it.
The value main denotes is an infinite program:
main = do
line <- getLine
putStrLn line
line <- getLine
putStrLn line
line <- getLine
putStrLn line
line <- getLine
putStrLn line
line <- getLine
putStrLn line
line <- getLine
putStrLn line
...
But it's represented in memory as a recursive structure that references itself. That representation is finite, unless someone tries to unfold the entire thing to get a non-recursive representation of the entire program - that would never finish.
But just as you can probably figure out how to start executing the infinite program I wrote above without waiting for me to tell you "all" of it, so can Haskell's runtime system figure out how to execute main without unfolding the recursion up-front.
Haskell's lazy evaluation is actually interleaved with the runtime system's execution of the main IO program, so this works even for a function that returns an IO action which recursively invokes the function, like:
main = foo 1
foo :: Integer -> IO ()
foo x = do
print x
foo (x + 1)
Here foo 1 is not a recursive value (it contains foo 2, not foo 1), but it's still an infinite program. However this works just fine, because the program denoted by foo 1 is only generated lazily on-demand; it can be produced as the runtime system's execution of main goes along.
By default Haskell's laziness means that nothing is evaluated until it's needed, and then only "just enough" to get past the current block. Ultimately the source of all the "need" in "until it's needed" comes from the runtime system needing to know what the next step in the main program is so it can execute it. But it's only ever the next step; the rest of the program after that can remain unevaluated until after the next step has been fully executed. So infininte programs can be executed and do useful work so long as it's always only a finite amount of work to generate "one more step".
I am still struggling with Haskell and now I have encountered a problem with wrapping my mind around the Input/Output monad from this example:
main = do
line <- getLine
if null line
then return ()
else do
putStrLn $ reverseWords line
main
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
I understand that because functional language like Haskell cannot be based on side effects of functions, some solution had to be invented. In this case it seems that everything has to be wrapped in a do block. I get simple examples, but in this case I really need someone's explanation:
Why isn't it enough to use one, single do block for I/O actions?
Why do you have to open completely new one in if/else case?
Also, when does the -- I don't know how to call it -- "scope" of the do monad ends, i.e. when can you just use standard Haskell terms/functions?
The do block concerns anything on the same indentation level as the first statement. So in your example it's really just linking two things together:
line <- getLine
and all the rest, which happens to be rather bigger:
if null line
then return ()
else do
putStrLn $ reverseWords line
main
but no matter how complicated, the do syntax doesn't look into these expressions. So all this is exactly the same as
main :: IO ()
main = do
line <- getLine
recurseMain line
with the helper function
recurseMain :: String -> IO ()
recurseMain line
| null line = return ()
| otherwise = do
putStrLn $ reverseWords line
main
Now, obviously the stuff in recurseMain can't know that the function is called within a do block from main, so you need to use another do.
do doesn't actually do anything, it's just syntactic sugar for easily combining statements. A dubious analogy is to compare do to []:
If you have multiple expressions you can combine them into lists using ::
(1 + 2) : (3 * 4) : (5 - 6) : ...
However, this is annoying, so we can instead use [] notation, which compiles to the same thing:
[1+2, 3*4, 5-6, ...]
Similarly, if you have multiple IO statments, you can combine them using >> and >>=:
(putStrLn "What's your name?") >> getLine >>= (\name -> putStrLn $ "Hi " ++ name)
However, this is annoying, so we can instead use do notation, which compiles to the same thing:
do
putStrLn "What's your name?"
name <- getLine
putStrLn $ "Hi " ++ name
Now the answer to why you need multiple do blocks is simple:
If you have multiple lists of values, you need multiple []s (even if they're nested).
If you have multiple sequences of monadic statements, you need multiple dos (even if they're nested).
I have a program in haskell that has to read arbitrary lines of input from the user and when the user is finished the accumulated input has to be sent to a function.
In an imperative programming language this would look like this:
content = ''
while True:
line = readLine()
if line == 'q':
break
content += line
func(content)
I find this incredibly difficult to do in haskell so I would like to know if there's an haskell equivalent.
The Haskell equivalent to iteration is recursion. You would also need to work in the IO monad, if you have to read lines of input. The general picture is:
import Control.Monad
main = do
line <- getLine
unless (line == "q") $ do
-- process line
main
If you just want to accumulate all read lines in content, you don't have to do that. Just use getContents which will retrieve (lazily) all user input. Just stop when you see the 'q'. In quite idiomatic Haskell, all reading could be done in a single line of code:
main = mapM_ process . takeWhile (/= "q") . lines =<< getContents
where process line = do -- whatever you like, e.g.
putStrLn line
If you read the first line of code from right to left, it says:
get everything that the user will provide as input (never fear, this is lazy);
split it in lines as it comes;
only take lines as long as they're not equal to "q", stop when you see such a line;
and call process for each line.
If you didn't figure it out already, you need to read carefully a Haskell tutorial!
It's reasonably simple in Haskell. The trickiest part is that you want to accumulate the sequence of user inputs. In an imperative language you use a loop to do this, whereas in Haskell the canonical way is to use a recursive helper function. It would look something like this:
getUserLines :: IO String -- optional type signature
getUserLines = go ""
where go contents = do
line <- getLine
if line == "q"
then return contents
else go (contents ++ line ++ "\n") -- add a newline
This is actually a definition of an IO action which returns a String. Since it is an IO action, you access the returned string using the <- syntax rather than the = assignment syntax. If you want a quick overview, I recommend reading The IO Monad For People Who Simply Don't Care.
You can use this function at the GHCI prompt like this
>>> str <- getUserLines
Hello<Enter> -- user input
World<Enter> -- user input
q<Enter> -- user input
>>> putStrLn str
Hello -- program output
World -- program output
Using pipes-4.0, which is coming out this weekend:
import Pipes
import qualified Pipes.Prelude as P
f :: [String] -> IO ()
f = ??
main = do
contents <- P.toListM (P.stdinLn >-> P.takeWhile (/= "q"))
f contents
That loads all the lines into memory. However, you can also process each line as it is being generated, too:
f :: String -> IO ()
main = runEffect $
for (P.stdinLn >-> P.takeWhile (/= "q")) $ \str -> do
lift (f str)
That will stream the input and never load more than one line into memory.
You could do something like
import Control.Applicative ((<$>))
input <- unlines . takeWhile (/= "q") . lines <$> getContents
Then input would be what the user wrote up until (but not including) the q.