一个简单的问题: 根据定义,(来自Haskell SOE)
do x — el; el\ ...; en
=> el »= \x — do e2\ ...; en
和:
do let decllist; el\...; en
=> let decllist in do e2\ ...; en
似乎这两个结构是相同的:
do let x = e1
e2
和
do x <- e1
e2
评估e1,将其绑定到e2,然后评估e2。
是
答案 0 :(得分:4)
让我们在Maybe
monad:
foo = do
let x = Just 1
return x
和
bar = do
x <- Just 1
return x
Desugaring both,我们得到了
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
供参考,我使用的是translation from section 3.14 of the Haskell 2010 Report。
答案 1 :(得分:3)
do let x = getLine
print x
转换为
let x = getLine in print x
这是类型错误,因为x
的类型为IO String
。我们要求打印计算本身,而不是结果。
do x <- getLine
print x
转换为
getLine >>= \x -> print x
此处x
作为计算结果绑定,其类型为String
,因此此类型会检查。
在do
- 表示法中,let
只是将值绑定到名称一样,而<-
用于执行monadic绑定,即将名称绑定到结果计算。
答案 2 :(得分:1)
假设e1
是Monad m => m a
类型的计算,那么let x = e1
和x <- e1
意味着有些不同。
在let
- 版本中,当您在do-expression中使用x
时,您正在处理类型为Monad m => m a
的值。
在另一个版本中,当您在do表达式中使用x
时,您正在处理类型a
的值(因为do-notation隐式处理monad上的映射)。
例如:
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
答案 3 :(得分:0)
没有。 x <- e1
转换为e1 >>= \x ->
,表达不完整; let
表达式只是普通let
。或者您在问let
和(>>=)
是否相同?它们非常不是:(>>=)
将monad包装的东西暴露给一个函数,该函数必须生成包含在monad中的东西。换句话说,对于x <- e1
,某些e1
的{{1}}类型必须为IO a
,但a
let x = e1
的类型为只是e1
;在这两种情况下,a
的类型都是x
。