Haskell Monadic forms
A simple question: given the definitions, (From Haskell SOE)
do x — el; el\ ...; en
=> el »= \x — do e2\ ...; en
and:
do let decllist; el\...; en
=> let decllist in do e2\ ...; en
it seems that these two constructs are the same:
do let x = e1
e2
and
do x <- e1
e2
开发者_开发知识库
both evaluate e1, bind it to e2, and then evaluate e2.
Yes?
Let's do a simple example in the Maybe
monad:
foo = do
let x = Just 1
return x
and
bar = do
x <- Just 1
return x
Desugaring both, we get
foo = let x = Just 1 in return x -- do notation desugaring
= return (Just 1) -- let
= Just (Just 1) -- definition of return for the Maybe monad
bar = let ok x = return x in Just 1 >>= ok -- do notation desugaring
= let ok x = return x in ok 1 -- definition of >>= for the Maybe monad
= return 1 -- definiton of ok
= Just 1 -- definition of return for the Maybe monad
For reference, I am using the translation from section 3.14 of the Haskell 2010 Report.
No, they are not the same. For example,
do let x = getLine
print x
translates to
let x = getLine in print x
this is a type error, as x
will have the type IO String
. We're asking to print the computation itself, not its result.
do x <- getLine
print x
translates to
getLine >>= \x -> print x
Here x
is bound as the result of the computation and its type is String
, so this type checks.
In do
-notation, let
just binds values to names like it always does, while <-
is used to perform monadic binding, which is binding a name to the result of a computation.
Assuming e1
is a computation of type Monad m => m a
, then let x = e1
and x <- e1
mean somewhat different things.
In the let
-version, when you use x
within a do-expression, you are dealing with a value of type Monad m => m a
.
In the other version, when you use x
within a do expression, you are dealing with a value of type a
(since do-notation implicitly handles mapping over the monad).
For example:
e :: IO Int
f :: Int -> Int
-- the following will result in a type error, since f operates on `Int`, not `IO Int`:
g = do let x = e
return $ f x
-- the following will work:
g' = do x <- e
return $ f x
No. x <- e1
translates to e1 >>= \x ->
, an incomplete expression; the let
expression is just a normal let
. Or are you asking if let
and (>>=)
are the same thing? They very much aren't: (>>=)
exposes the thing wrapped by a monad to a function, which must produce something wrapped in the monad. In other words, with x <- e1
, e1
's type must be IO a
for some a
, but with let x = e1
e1
's type is just a
; in both cases the type of x
will be a
.
精彩评论