LYAH-链接Writer monad时了解有关“ tell”的注释

问题描述 投票:6回答:1

问题在底部以粗体显示。

LYAH给出了将do符号与Writer单子一起使用的示例

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)))

然后这本书提出了一个我不太清楚的观点,即使不是很准确:

return (a*b)是最后一行很重要,因为do表达式中最后一行的结果是整个do表达式的结果。如果我们将tell作为最后一行,则()将是此do表达式的结果。我们将失去乘法的结果。但是,日志将相同。

因此,我的第一个疑问是:如果tell结果为(),则代码不应该甚至不编译,因为()无法匹配预期的类型Int,也无法匹配其他类型比()本身;那作者想告诉我们什么呢?为了使这种基于非观点的观点,自从编写本书以来,Haskell进行了一些更改,使上面引用的陈述不清楚/不准确?

haskell monads
1个回答
4
投票

等效的重写是进一步的

multWithLog = logNumber 3 >>= (\x ->
              logNumber 5 >>= (\y ->
              tell ["something"] >>= (\() ->     -- () NB
              return (x*y) >>= (\result ->
              return result ))))

that()“返回”的tell ["something"]。显然,改组

multWithLog2 = logNumber 3 >>= (\x ->
               logNumber 5 >>= (\y ->
               return (x*y) >>= (\result ->
               tell ["something"] >>= (\() ->
               return () ))))

确实具有类型Writer [String] (),因此,如果签名指定为Writer [String] Int,则它的确不会编译。

没有类型签名问题,“ log”,即,所收集的[String]列表对于两个变体都是相同的,因为return不会更改所收集的输出“ log”。

© www.soinside.com 2019 - 2024. All rights reserved.