I wrote a Haskell function that calculates the factorial of every number in a given list and prints it to the screen.
factPrint list =
if null list
then putStrLn ""
else do putStrLn ((show.fact.head) list)
factPrint (tail list)
The function works, but I find the third line a bit confusing.
Why hasn't the compiler(GHC) reported an error on it since there is no "do" before the "putStrLn" (quasi?)function?
If I omit "do" from the 4th line, an error pops up as expected.
I'm quite new to Haskell and its ways, so please pardon me if I said something overly silly.
do putStrLn ((show.fact.head) list)
factPrint (tail list)
is actually another way of writing
putStrLn ((show.fact.head) list) >> factPrint (tail list)
which, in turn, means
putStrLn ((show.fact.head) list) >>= \_ -> factPrint (tail list)
The do notation is a convenient way of stringing these monads together, without this other ugly syntax.
If you only have one statement inside the do, then you are not stringing anything together, and the do is redundant.
If you are new to Haskell, think of do as similar to required braces after if in a C-like language:
if (condition)
printf("a"); // braces not required
else {
printf("b"); // braces required
finish();
}
do works the same way in Haskell.
Maybe it would help to look at the type of factPrint, and then refactor to use pattern matching:
factPrint :: [Int] -> IO ()
factPrint [] = putStrLn ""
factPrint list = do
putStrLn (show.fact.head) list
factPrint (tail list)
So, if factPrint returns IO (), and the type of putStrLn "" is IO (), then it's perfectly legal for factPrint [] to equal putStrLn "". No do required--in fact, you could just say factPrint [] = return () if you didn't want the trailing newline.
do is used to tie multiple monadic expressions together. It has no effect when followed by only a single expression.
For the if to be well-formed it is only necessary that the then-clause and the else-clause have the same type. Since both clauses have the type IO () this is the case.
The do keyword is used for sequencing, an if-then-else in Haskell doesn't have to contain a do at all if each branch is a single statement eg.
if a
then b
else c
You need the do in your example as you are sequencing two operations on your else branch. If you omit the do then the factPrint(tail list) statement is considered to not be part of the function and thus the compiler complains as it's encountered an unexpected statement.
Related
If Haskell is lazy, why does getLine is evaluated in both of the following cases? Being lazy I would expect that in the case of fa the getLine would not be evaluated because its result is not being used subsequently:
let fa = do {
x <- getLine;
return "hello"
}
let fb = do {
x <- getLine;
return $ x
}
(I tested both cases in GHCi)
Thanks
Its result is being used, just not in the way you necessarily expect. This de-sugars to
fa = getLine >>= (\x -> return "hello")
So the result of getLine is still passed to the function \x -> return "hello". Monads are inherently about sequencing actions together (among other things); that sequencing still occurs even if results are later not used. If that weren't the case, then
main = do
print "Hello"
print "World"
wouldn't do anything as a program, since the results of both calls to print aren't being used.
Congratulations, you've just discovered why Haskell is a pure functional language!
The result† of getLine is not a string. It's an IO action which happens to “produce” a string. That string is indeed not evaluated, but the action itself is (since it turns up in a do block bound to main), and this is all that matters as far as side-effects are concerned.
†Really just the value of getLine. This is not a function, so it doesn't actually have a result.
Be careful now... ;-)
The result of getLine isn't a string, it's an "I/O command object", if you will. The code actually desugars to
getLine >>= (\ x -> return "hello")
The >>= operator constructs a new I/O command object out of an existing one and a function... OK, that's a bit much to wrap your mind around. The important thing is, the I/O action gets executed (because of the implementation of >>= for IO), but its result doesn't necessarily get evaluated (because of laziness).
So let's look at the implementation of the IO monad... erm, actually you know what? Let's not. (It's deep magic, hard-wired into the compiler, and as such it's implementation-specific.) But this phenomenon isn't unique to IO by any means. Let's look at the Maybe monad:
instance Monad Maybe where
mx >>= f =
case mx of
Nothing -> Nothing
Just x -> f x
return x = Just x
So if I do something like
do
x <- foobar
return "hello"
Will x get evaluated? Let's look. It desugars to:
foobar >>= (\ x -> return "hello")
then this becomes
case foobar of
Nothing -> Nothing
Just x -> Just "hello"
As you can see, foobar is clearly going to be evaluated, because we need to know whether the result is Nothing or Just. But the actual x won't be evaluated, because nothing looks at it.
It's kind of the same way that length evaluates the list nodes, but not the list elements they point to.
I would like to allow a user to build a list from a series of inputs in Haskell.
The getLine function would be called recursively until the stopping case ("Y") is input, at which point the list is returned.
I know the function needs to be in a similar format to below. I am having trouble assigning the correct type signatures - I think I need to include the IO type somewhere.
getList :: [String] -> [String]
getList list = do line <- getLine
if line == "Y"
then return list
else getList (line : list)
So there's a bunch of things that you need to understand. One of them is the IO x type. A value of this type is a computer program that, when later run, will do something and produce a value of type x. So getLine doesn't do anything by itself; it just is a certain sort of program. Same with let p = putStrLn "hello!". I can sequence p into my program multiple times and it will print hello! multiple times, because the IO () is a program, as a value which Haskell happens to be able to talk about and manipulate. If this were TypeScript I would say type IO<x> = { run: () => Promise<x> } and emphatically that type says that the side-effecting action has not been run yet.
So how do we manipulate these values when the value is a program, for example one that fetches the current system time?
The most fundamental way to chain such programs together is to take a program that produces an x (an IO x) and then a Haskell function which takes an x and constructs a program which produces a y (an x -> IO y and combines them together into a resulting program producing a y (an IO y.) This function is called >>= and pronounced "bind". In fact this way is universal, if we add a program which takes any Haskell value of type x and produces a program which does nothing and produces that value (return :: x -> IO x). This allows you to use, for example, the Prelude function fmap f = (>>= return . f) which takes an a -> b and applies it to an IO a to produce an IO b.
So It is so common to say things like getLine >>= \line -> putStrLn (upcase line ++ "!") that we invented do-notation, writing this as
do
line <- getLine
putStrLn (upcase line ++ "!")
Notice that it's the same basic deal; the last line needs to be an IO y for some y.
The last thing you need to know in Haskell is the convention which actually gets these things run. That is that, in your Haskell source code, you are supposed to create an IO () (a program whose value doesn't matter) called Main.main, and the Haskell compiler is supposed to take this program which you described, and give it to you as an executable which you can run whenever you want. As a very special case, the GHCi interpreter will notice if you produce an IO x expression at the top level and will immediately run it for you, but that is very different from how the rest of the language works. For the most part, Haskell says, describe the program and I will give it to you.
Now that you know that Haskell has no magic and the Haskell IO x type just is a static representation of a computer program as a value, rather than something which does side-effecting stuff when you "reduce" it (like it is in other languages), we can turn to your getList. Clearly getList :: IO [String] makes the most sense based on what you said: a program which allows a user to build a list from a series of inputs.
Now to build the internals, you've got the right guess: we've got to start with a getLine and either finish off the list or continue accepting inputs, prepending the line to the list:
getList = do
line <- getLine
if line == 'exit' then return []
else fmap (line:) getList
You've also identified another way to do it, which depends on taking a list of strings and producing a new list:
getList :: IO [String]
getList = fmap reverse (go []) where
go xs = do
x <- getLine
if x == "exit" then return xs
else go (x : xs)
There are probably several other ways to do it.
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'm very new to Haskell and I'm trying to understand these basic lines of code. I have a main module that's very simple:
main = do
words <- readFile "test.txt"
putStrLn $ reverseCharacters words
where reverseCharacters is defined in another module that I have:
reverseCharacters :: String -> String
reverseCharacters x = reverse x
What I am having trouble understanding is why the $ needs to be there. I've read previous posts and looked it up and I'm still having difficulty understanding this. Any help would be greatly appreciated.
$ is an operator, just like +. What it does is treat its first argument (the expression on the left) as a function, and apply it to its second argument (the expression on the right).
So in this case putStrLn $ reverseCharacters words is equivalent to putStrLn (reverseCharacters words). It needs to be there because function application is left associative, so using no $ or parentheses like putStrLn reverseCharacters words would be equivalent to parenthesising this way (putStrLn reverseCharacters) words, which doesn't work (we can't apply putStrLn to reverseCharacters [something of type String -> String], and even if we could we can't apply the result of putStrLn to words [something of type String]).
The $ operator is just another way of explicitly "grouping" the words than using parentheses; because it's an infix operator it forces a "split" in the expression (and because it's a very low precedence infix operator, it works even if the things on the left or right are using other infix operators).
writeStr []=putChar ' '
writeStr (x:xs) = (putChar x)(writeStr xs)
Hello, and thanks in advance, i get a type error, it should be a simple answer but i just dont get where the error is coming from.
Your code is a bit strange. If I got it right, you try to print a string. Your method is to put the first string, and than the second. But it's not possible in Haskell to combine two IO actions like this. Have a look in your tutorial again about this, here's hwo it could look like:
writeStr [] = return () -- you had putChar ' ',
writeStr (x:xs) = do putChar x -- but this would print a superfluous whtiespace
writeStr xs
If you want to do several things sequentially, either use the do-keyword or monadic combinators. Its very easy, just like this:
do action1
action2
action3
...
FUZxxl has answered the immediate question, but I'd like to expand on it with some more ways of writing "writeStr" to illustrate more about monads.
As delnan said in the comments, you can also write
writeStr [] = return ()
writeStr (x:xs) = putChar x >> writeStr xs
This is actually the "desugared" version of the "do" notation. The ">>" operator is used to daisy-chain monadic actions together. Its actually a specialised version of the "bind" operator, written ">>=". See this question for more details.
But when you look at this, it seems that all we are doing is applying "putChar" to each element in the argument list. There is already a function in the Prelude called "map" for doing this, so maybe we could write:
writeStr xs = map putChar xs
But when you try that it won't work. The reason becomes evident if you go into GHCi and type this:
:type map putChar "Hello"
[IO ()]
You want a single "IO()" action, but this gives you a list of them. What you need is a function that turns this list of IO actions into a single IO action. Fortunately one exists. The Prelude contains these two functions
sequence :: [IO a] -> IO [a]
sequence_ :: [IO a] -> IO ()
The first one is for when you want the list of results, the second is for cases where you don't, like this one. (Throughout this answer I'm going to be giving the IO-specific type signatures for clarity, but its important to remember that all these functions actually work for any monad.)
So now you can write:
writeStr xs = sequence_ $ map putChar xs
But there is a way of shortening this. Recall the "." operator, which sticks two functions together, and the way Haskell has of "currying" function arguments? We can rewrite the function above as:
writeStr = sequence_ . map putChar
This "point-free" style looks and feels very odd at first; it makes "writeStr" look more like a constant than a function. But it avoids the need to track variable names around the code when you are reading it, and so is often preferred. Its also a lot shorter and more readable when you are putting something complicated as the argument to "map" or similar higher order functions.
But we can go even shorter. The "sequence . map f" pattern is very common, so the "Control.Monad" module defines a couple more functions to embody it:
mapM :: (a -> IO b) -> [a] -> IO [b]
mapM f = sequence . map f
mapM_ :: (a -> IO b) -> [a] -> IO ()
mapM_ f = sequence_ . map f
So you can finally write
writeStr = mapM_ putChar