Reputation:
This code obviously works
import Data.Char
main = do
content <- readFile "in.txt"
writeFile "out.txt" (map toUpper content)
Why this one doesn't?
import Data.Char
main = do
writeFile "out.txt" (map toUpper $ <- readFile "in.txt")
Upvotes: 8
Views: 441
Reputation: 54068
The <-
"extracts" a value from a monadic container. IO
is a monad, and so it can be used to extract a value from an IO
action. However, the syntax of Haskell says that you must bind it to a name before using it. In actuality, the <-
isn't an operator at all, but syntactic sugar for the >>=
operator (pronounced "bind"). So when you write
main = do
contents <- readFile "in.txt"
writeFile "out.txt" (map toUpper contents)
It gets turned into
main = readFile "in.txt" >>= (\contents -> writeFile "out.txt" (map toUpper contents))
Now, imagine if you had a lot more statements in main
. Maybe you extracted several values with <-
, and some of the expressions used more than one of those values at a time. You could definitely write the "desugared" version, but it would start getting very, very difficult. The do-notation simplifies this and makes the compiler take care of it for you.
Upvotes: 6
Reputation: 120049
First, <-
is not an operator. It's a special syntax element that requires a pattern on the left side.
Second, if it were an infix operator, $ <-
would not work, as you cannot have two infix operators next to each other.
Upvotes: 16
Reputation: 363787
Because this is not how <-
is defined. It translates to
readFile "in.txt" >>= \content ->
writeFile "out.txt" (map toUpper content)
You could use =<<
instead:
writeFile "out.txt" . map toUpper =<< readFile "in.txt"
Upvotes: 16
Reputation: 944
you can to write it as follows
readFile "in.txt" >>= writeFile "out.txt" . map toUpper
Upvotes: 3