简体   繁体   中英

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 => ma , 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 => ma .

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM