【问题标题】:This is not a monad, right?这不是单子,对吧?
【发布时间】:2013-12-05 00:35:57
【问题描述】:
我看到两个消息来源说以下是一个身份单子。但我不认为这是真的,因为它不符合第三单子定律。
(defn result [v] (fn [] v))
(defn bind [mv f] (f (mv))
第三单子定律失败
(bind (bind (result 3) identity) identity)
内部bind调用返回3,不是monadic值,所以Java返回尝试调用函数的错误(3)。
我错过了什么吗?
【问题讨论】:
标签:
clojure
monads
identity
【解决方案1】:
bind 和 result 的定义很好,确实构成了一个 monad。但是,identity 不是为您的 monad 传递给 bind 的合法函数。在 Haskell 中,这不会通过类型检查器,因为
bind :: (Monad m) => m a -> (a -> m b) -> m b
这里的第二个参数是你的f,在本例中是identity。但是identity :: a -> a 不适合bind 的f 所需的类型。
为了在你的 monad 中使用“类似身份”的东西,你需要将 identity 与 result 组合到 monad 中。例如,
(let [id (comp result identity)] ;; or (liftm identity), if you have liftm
(bind (bind (result 3) id) id))
返回(result 3),即(fn [] 3)。
编辑
我对此进行了更多思考,因为我断言 a -> a 是与 a -> m b 不兼容的类型显然不太正确:如果您让 a 成为 m b,则类型确实匹配。所以在某些情况下可以使用identity 作为bind 函数。具体来说,如果您的原始输入是(result (result 3)),您可以bind identity 并直接退出(result 3)。其实(bind identity x)基本上就是(join x)!这并不完全是新闻——我已经读过很多遍了——但我想它还没有深入人心,或者我一开始就更正确地回答了这个问题。
无论如何,我只是想分享一下,因为它有点话题,应该充实我的答案。