我不知道何时必须使用let
以及何时必须使用<-
绑定。
答案 0 :(得分:4)
let
给出函数调用结果的名称。
<-
将当前monad中monadic操作的结果绑定到名称。
他们完全不同。使用let
作为monad之外的函数的结果,即普通的纯函数。使用<-
表示任何monadic,因为它“解包”monad结果并让你获得其中的值。
例如:
假设具有以下签名的IO功能
frobnicate :: String -> IO Bool
和纯函数
dothing :: Bool -> Bool
我们可以这样做
main :: IO ()
main = do
x <- frobnicate "Hello"
let y = frobnicate "Hello"
-- z <- dothing x
let z = dothing x
return ()
我们知道x :: Bool
,因为Bool
已从我们的IO
操作结果中提取(操作运行,结果称为x
所以我们可以在以后使用它。)
我们也知道y :: IO Bool
- 操作尚未运行,它是未来IO操作的潜力。因此,我们可以使用y
执行唯一有用的操作是稍后运行,绑定结果并以Bool
内部方式获取,但let
Bool
之后甚至还存在。
第三行被注释掉,因为它不会编译 - 你不能对不在相关monad中的操作进行monadic绑定。 dothing
不会返回IO
任何内容,因此您无法将其绑定到IO ()
函数中。
第四行很简单 - z
是dothing x
的结果,其中x
是从先前运行frobnicate "Hello"
解包的值。
所有这些只是下面“真正的”monad操作的语法糖,因此扩展(没有注释部分)类似
main = frobnicate "Hello" >>= (\x -> let y = frobnicate "Hello"
z = dothing x
in return ())
这个例子当然没有任何意义,但希望它能说明let
和<-
在do
符号中的区别。
TL; DR:使用<-
为monadic操作的结果命名,let
为其他所有操作命名。
答案 1 :(得分:3)
public function boot(Factory $validator)
{
require_once app_path() . '/validators.php';
}
是<-
(>>=
),其中bind
位于let
块中的fmap
。
从here窃取示例:
do
do x1 <- action1 x0
x2 <- action2 x1
action3 x1 x2
-- is equivalent to:
action1 x0 >>= \ x1 -> action2 x1 >>= \ x2 -> action3 x1 x2
,action1
&amp; action2
都返回某种monad,比如说:
action3
您可以重写let绑定:
action1 :: (Monad m) => a -> m b
action2 :: (Monad m) => b -> m c
action3 :: (Monad m) => b -> c -> m d
答案 2 :(得分:1)
可视化<-
的作用的一个很好的例子:
do
a <- ['a'..'z']
b <- [1..3]
pure (a,b)
您可以在try.frege-lang.org的在线REPL中尝试此操作 (您可以将其输入为单行:
do { a <- ['a'..'z']; b <- [1..3]; pure (a,b) }