哈斯克尔单体流理解



我将在底部用示例重申我的问题。

当我说mk时,我指的是函数调用中的左右值,m >>= k.

对monads的理解是模糊的。如果m是一个计算,k是一个lambda表达式,这是否意味着k有两个目的,它可以使用它来处理do块中的绑定,也可以用于Monad实例定义中的其他目的?如果一个值在其 do 块中被评估之前k绑定,值会自动传递给它,还是 Monad 实例方法定义,我们在其中定义了传播到k的唯一效果?

我看到的例子可能有点误导,这些例子在解释 monads 时总是将直接的前一个绑定项传递给 lambda 表达式。即使使用的符号是纯 do-no-lambda,它是否始终是传递给隐藏的 lambda 的最后一个绑定项,在引擎盖下。现在,使用接受多个参数的 lambda 并将其用作m >>= k中的k是一种不好的做法吗?或者我假设如果我们在一个 do 块中工作,在引擎盖下,只有一个参数传递给下一个"隐藏"的 lambda 表达式,并且这个参数是紧接的先前绑定项目,这是否是错误的?

我现在用例子重申我的问题。

do
a <- getLine
b <- getLine
putStrLn $ a ++ b

ab绑定到从运行getLine返回IO容器中的值。在引擎盖下,以下哪项是等效的(如果有的话)?

getLine >>= a -> getLine >>= b -> putStrLn (a ++ b)

getLine >>= a -> getLine >>= (a, b) -> putStrLn (a ++ b)

我们看到getLineIO容器中的值被提取并传递给 lambda 表达式。

如果第一个是正确的,那不会导致错误,因为a在 monad 定义中是未定义的?

我凭空拉出了第二个。我没有看到任何证据表明可能是这样的,但即使它不是正确的答案,我们能做这样的事情吗?当然,在这种情况下,我们必须使所有与>>=一起使用的 lambda 表达式都采用 2 元组。这种行为不完全是由我们的>>=定义决定的,至少在使用 only-lambda-no-do 表示法时是这样?

我们可以在 monad 定义中使用此 lambda 表达式并向它传递一些内容,使其再次打印屏幕吗?我们应该吗?

如果我们想在>>=定义中使用putStrLn,我们是否必须向k传递一些任意值才能得到putStrLn函数?

谢谢。和平。

do

这样的表示法:

do
a <- getLine
b <- getLine
putStrLn $ a ++ b

相当于

getLine >>= a -> getLine >>= b -> putStrLn (a ++ b)

这又相当于

getLine >>= (a -> getLine >>= b -> putStrLn (a ++ b))

请注意额外的括号。第一个getLine由一个 lambda 表达式组成,其中a是"包含的元素"。在此 lambda 表达式中,将调用一个新表达式。该表达式是

getLine >>= b -> putStrLn (a ++ b)

此表达式仍然"在"第一个 lambda 表达式内,这意味着a仍在范围内。

如果有帮助,您可以在表达式周围添加更多括号:

getLine >>= (a -> getLine >>= (b -> putStrLn (a ++ b)))

这些括号是完全多余的,但它们突出显示了各种表达式的作用域。请注意,调用putStrLn (a ++ b)时,ab仍在范围内。

我只会给你一个部分答案,因为我不明白,你到底在问什么。对不起。

do
a <- getLine
b <- getLine
putStrLn $ a ++ b

相当于

getLine >>= a -> getLine >>= b -> putStrLn (a ++ b)

这有效,因为

b -> putStrLn (a ++ b)

创建一个函数,该函数从定义的范围内捕获a在。如果 在此术语范围内没有此类a,编译器将抱怨a不在范围内。

让我们稍微扩展一下,看看

a -> getLine >>= b -> putStrLn (a ++ b)

再。这定义了一个函数,如果应用于某个值x则返回表达式的结果

getLine >>= b -> putStrLn (x ++ b)

在这里,变量a被值x替换。因此,无需再担心a

无糖do block就像getLine >>= a -> getLine >>= b -> putStrLn (a ++ b)由于本地作用域而不需要传递先前调用的所有参数,让我们表示它们:

getLine >>= 
(!This is first closure! a -> getLine >>= 
(!This is second, all variables from the first 
closure are available, because in haskell function closure takes outer scope in! b -> 
putStrLn(a ++ b) !End of the second closure!) !End of the first closure!)

现在关于 (>>=) 的类型。GHCI打印下一个(>>=) :: Monad m => m a -> (a -> m b) -> m b. 所以k只是一个Monad m将使用的lambda,它所要做的就是为>>="实现接口"。

do是否等同于以下内容?

getLine >>= a -> getLine >>= b -> putStrLn (a ++ b)

是的,这个。

如果第一个是正确的,那不会导致错误,因为在 monad 定义中未定义 a?

不。->箭头语法是右关联的:

getLine >>= (a -> getLine >>= (b -> putStrLn (a ++ b)))

它形成一个闭包,a仍在范围内。

最新更新