寻求对 monad 实施的建设性批评

Posted

技术标签:

【中文标题】寻求对 monad 实施的建设性批评【英文标题】:Seeking constructive criticism on monad implementation 【发布时间】:2011-06-13 12:13:54 【问题描述】:

我正在学习 monad,这是我的第一个工作(除了琐碎的 monad)。随意无情地批评其中的一切。我对“更惯用”和“更优雅”的响应方式特别感兴趣。

这个 monad 计算执行的绑定次数。

data C a = C value :: a, count :: Int deriving (Show)

instance Monad C where
    (>>=) (C x c) f = C (value $ f x) (c + 1)
    return x = C x 0

add :: (Num a) => a -> a -> C a
add x y = return $ x + y

-- Simpler way to do this? foldM is obviously something different.
mysum [x] = return x
mysum (x:xs) = mysum xs >>= add x

【问题讨论】:

【参考方案1】:

从风格上讲,这非常好。在现实世界中,我预计这种符号的可能性为 60%,而不是您给出的那个:

C x c >>= f = C (value $ f x) (c + 1)

但这太小了,几乎不值得一提。

更严肃地说,不是文体而是语义:这不是单子。事实上,它违反了所有三个单子定律。

(1) return x >>= f  =  f x
(2) m >>= return    = m
(3) m >>= (f >=> g) = (m >>= f) >>= g

(其中(>=>)被定义为f >=> g = \x -> f x >>= g。如果(>>=)被认为是一个“应用”运算符,那么(>=>)就是对应的组合运算符。我喜欢用这个运算符陈述第三定律,因为它带来了出第三定律的含义:结合性。)

通过这些计算:

(1):

return 0 >>= return 
  = C 0 0 >>= return
  = C (value $ return 0) 1
  = C 0 1
Not equal to return 0 = C 0 0

(2):

C 0 0 >>= return
  = C (value $ return 0) 1
  = C 0 1
Not equal to C 0 0

(3)

C 0 0 >>= (return >=> return)
  = C (value $ (return >=> return) 0) 1
  = C (value $ return 0 >>= return) 1
  = C (value $ C 0 1) 1
  = C 0 1

Is not equal to:

(C 0 0 >>= return) >>= return
  = C (value $ return 0) 1 >>= return
  = C 0 1 >>= return
  = C (value $ return 0) 2
  = C 0 2

这不仅仅是您的实现中的错误——没有“计算绑定数量”的 monad。它必须违反法律 (1) 和 (2)。但是,您违反法律 (3) 的事实是实施错误。

问题在于(>>=) 的定义中的f 可能会返回一个包含多个绑定的操作,而您忽略了这一点。您需要添加左右参数的绑定数量:

C x c >>= f = C y (c+c'+1)
   where
   C y c' = f x

这将正确计算绑定的数量,并满足第三定律,即结合定律。它不会满足其他两个。然而,如果你从这个定义中去掉+1,那么你确实得到一个真正的monad,它相当于Writer monad 在+ monoid 之上。这基本上将所有子计算的结果加在一起。您可以使用它来计算 somethings 的数量,而不是绑定 - 绑定太特殊而无法计算。但是,例如:

tick :: C ()
tick = C () 1

然后C 将统计计算中发生的ticks 的数量。

实际上,您可以将Int 替换为任何类型,将(+) 替换为任何关联 运算符并获得一个monad。这就是Writer monad 的一般含义。如果运算符不是关联的,那么这将不符合第三定律(你明白为什么吗?)。

【讨论】:

这不是我所期望的,但肯定是我需要的。关于如果运算符不是关联的,为什么会破坏第三定律:因为第三定律是绑定的关联性。如果 bind “做”某事不具有关联性(我不能给出“做”的确切定义),那么它本身也不能是关联的。对吗? 还有:漂亮的深入解释。谢谢。

以上是关于寻求对 monad 实施的建设性批评的主要内容,如果未能解决你的问题,请参考以下文章

批评与自我批评

挨批评了!Chrome 对用户隐私保护还不如 IE?

Vue学习之路---No.6(分享心得,欢迎批评指正)

表扬?批评?

美联储周三无惊喜,降息25个基点:再次获川普严重批评

领导误解了你,批评了你,请务必用上这个锦囊