[英]Haskell Monadic forms
一个简单的问题:给定定义,(来自 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。
是的?
让我们在Maybe
monad 中做一个简单的例子:
foo = do
let x = Just 1
return x
和
bar = do
x <- Just 1
return x
对两者都进行脱糖,我们得到
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
作为参考,我使用的是 Haskell 2010 报告第 3.14 节的翻译。
不,它们不一样。 例如,
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
-notation 中, let
像往常一样将值绑定到名称,而<-
用于执行单子绑定,即将名称绑定到计算结果。
假设e1
是Monad m => ma
类型的计算,那么let x = e1
和x <- e1
意味着有些不同的东西。
在let
版本中,当您在 do 表达式中使用x
时,您正在处理Monad m => ma
类型的值。
在另一个版本中,当您在 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
没有。 x <- e1
转换为e1 >>= \x ->
,一个不完整的表达式; let
表达式只是一个普通的let
。 或者您是在问let
和(>>=)
是否相同? 它们不是: (>>=)
将被 monad 包裹的东西暴露给 function,它必须产生包裹在 monad 中的东西。 换句话说,对于x <- e1
,对于某些a
, e1
的类型必须是IO a
,但是对于let x = e1
e1
的类型只是a
; 在这两种情况下, x
的类型都是a
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.