寻求对 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
将统计计算中发生的tick
s 的数量。
实际上,您可以将Int
替换为任何类型,将(+)
替换为任何关联 运算符并获得一个monad。这就是Writer
monad 的一般含义。如果运算符不是关联的,那么这将不符合第三定律(你明白为什么吗?)。
【讨论】:
这不是我所期望的,但肯定是我需要的。关于如果运算符不是关联的,为什么会破坏第三定律:因为第三定律是绑定的关联性。如果 bind “做”某事不具有关联性(我不能给出“做”的确切定义),那么它本身也不能是关联的。对吗? 还有:漂亮的深入解释。谢谢。以上是关于寻求对 monad 实施的建设性批评的主要内容,如果未能解决你的问题,请参考以下文章