haskell - LYAH - 在链接 Writer monad 时理解关于 "tell"的评论

标签 haskell monads do-notation rewriting writer-monad

问题在底部以粗体显示。
LYAH 给出了使用 do 的示例Writer 的符号单子(monad)

import Control.Monad.Writer

logNumber :: Int -> Writer [String] Int
logNumber x = writer (x, ["number " ++ show x])

multWithLog :: Writer [String] Int
multWithLog = do
              a <- logNumber 3
              b <- logNumber 5
              return (x*y)
可以在没有 do 的情况下重写定义符号:
multWithLog = logNumber 3 >>= (\x ->
              logNumber 5 >>= (\y ->
              return (x*y)))
到目前为止,一切都很好。
之后本书介绍tell , 并编辑 multWithLog 的定义像这样:
multWithLog = do
              a <- logNumber 3
              b <- logNumber 5
              tell ["something"]
              return (x*y)
这又可以重写为:
multWithLog = logNumber 3 >>= (\x ->
              logNumber 5 >>= (\y ->
              tell ["something"] >>
              return (x*y)))
然后这本书提出了一个对我来说似乎不清楚的观点,如果不是不准确的话:

It's important that return (a*b) is the last line, because the result of the last line in a do expression is the result of the whole do expression. Had we put tell as the last line, () would have been the result of this do expression. We'd lose the result of the multiplication. However, the log would be the same.


因此,我的第一个疑问来了:如果 tell结果 () ,那么代码不应该也不应该编译,因为 ()无法匹配预期类型 Int , 也不是 () 以外的任何其他类型本身;那么作者想告诉我们什么?为了使这个非基于意见,自从本书编写以来,Haskell 中是否发生了一些变化,导致上述引用的陈述不清楚/不准确?

最佳答案

等效的重写是进一步

multWithLog = logNumber 3        >>= (\ x ->
              logNumber 5        >>= (\ y ->
              tell ["something"] >>= (\ () ->     -- () NB
              return (x*y)       >>= (\ result ->
              return result ))))
那就是()tell ["something"] “回归”。显然,洗牌
multWithLog2 = logNumber 3        >>= (\ x ->
               logNumber 5        >>= (\ y ->
               return (x*y)       >>= (\ result ->
               tell ["something"] >>= (\ () ->
               return () ))))
确实会有类型 Writer [String] () , 所以如果签名指定 Writer [String] Int ,它确实不会编译。
没有类型签名问题,即“日志”,即收集的 [String]两个变体的列表将相同,如 return不会更改收集的输出“日志”。

关于haskell - LYAH - 在链接 Writer monad 时理解关于 "tell"的评论,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62182040/

相关文章:

c# - 状态设计模式的功能等价物

haskell - where 子句中的 IO

javascript - 函数式 javascript 读取、异步、写入结果

haskell - Haskell Monads 中的 `let .. in do` 和 `<-` 表示法有什么区别?

haskell - 使用防护装置正确的缩进规则

haskell - let 语句中的 case 语句需要什么缩进?

algorithm - Haskell - 如何使用列表 monad 在井字游戏中生成下一步

haskell - Hask 或 Agda 有均衡器吗?

haskell - 使用foldl/foldr从字符串中删除元素

haskell - 单子(monad)只是内仿函数类别中的一个幺半群,有什么问题?