寻求对 monad 实现的建设性批评 [英] Seeking constructive criticism on monad implementation

查看:19
本文介绍了寻求对 monad 实现的建设性批评的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm learning monads, this is my first working one (aside from the trivial monad). Feel free to criticize everything in it ruthlessly. I'm especially interested in "more idiomatic" and "more elegant" kind of responses.

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

This monad counts the number of binds performed.

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

推荐答案

这在风格上非常好.在现实世界中,我希望有 60% 的机会使用这种表示法,而不是您提供的这种表示法:

Stylistically this is very nice. In the real world, I would expect a 60% chance of this notation instead of the one you gave:

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

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

But that is so minor it is hardly worth mentioning.

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

On a more serious note, not stylistic but semantic: this is not a monad. In fact, it violates all three of the monad laws.

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

(其中 (>=>) 定义为 f >=> g = x -> fx >>= g.如果 (>>=) 被认为是一个应用程序"操作符,那么 (>=>) 是相应的组合操作符.我想说第三个定律使用这个运算符,因为它带出了第三定律的含义:结合性.)

(Where (>=>) is defined as f >=> g = x -> f x >>= g. If (>>=) is considered an "application" operator, then (>=>) is the corresponding composition operator. I like to state the third law using this operator because it brings out the third law's meaning: associativity.)

通过这些计算:

(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) 的事实是一个实施错误.

This isn't just an error in your implementation -- there is no monad that "counts the number of binds". It must violate laws (1) and (2). The fact that yours violates law (3) is an implementation error, however.

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

The trouble is that f in the definition of (>>=) might return an action that has more than one bind, and you are ignoring that. You need to add the number of binds from the left and right arguments:

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

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

This will correctly count the number of binds, and will satisfy the third law, which is the associativity law. It won't satisfy the other two. However, if you drop the +1 from this definition, then you do get a real monad, which is equivalent to the Writer monad over the + monoid. This basically adds together the results of all subcomputations. You could use this to count the number of somethings, just not binds -- bind is too special to count. But, for example:

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

然后 C 将计算计算中发生的 tick 的数量.

Then C will count the number of ticks that occurred in the computation.

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

In fact, you can replace Int with any type and (+) with any associative operator and get a monad. This is what a Writer monad is in general. If the operator is not associative, then this will fail the third law (can you see why?).

这篇关于寻求对 monad 实现的建设性批评的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆