9

Monad标准类是有缺陷的,它实际上应该扩展FunctorPointed浮动的想法。

我不一定声称这是正确的做法,但假设有人试图这样做:

import Prelude hiding (Monad(..))

class Functor m => Monad m where
    return :: a -> m a
    join :: m (m a) -> m a
    join = (>>= id)
    (>>=) :: m a -> (a -> m b) -> m b
    a >>= t = join (fmap t a)
    (>>) :: m a -> m b -> m b
    a >> b = a >>= const b

到目前为止一切顺利,但是当尝试使用 do-notation 时:

whileM :: Monad m => m Bool -> m ()
whileM iteration = do
    done <- iteration
    if done
        then return ()
        else whileM iteration

编译器抱怨:

Could not deduce (base:GHC.Base.Monad m) from the context (Monad m)

问题:

do-notation 仅适用于base:GHC.Base.Monad吗?有没有办法让它与替代Monad类一起工作?

额外的上下文:

我真正想做的是base:Control.Arrow.Arrow用“通用”Arrow类替换:

{-# LANGUAGE TypeFamilies #-}

class Category a => Arrow a where
    type Pair a :: * -> * -> *
    arr :: (b -> c) -> a b c
    first :: a b c -> a (Pair a b d) (Pair a c d)
    second :: a b c -> a (Pair a d b) (Pair a d c)
    (***) :: a b c -> a b' c' -> a (Pair a b b') (Pair a c c')
    (&&&) :: a b c -> a b c' -> a b (Pair a c c')

然后在Arrow我的课程中使用 's proc-notation Arrow,但这就像上面的 do-notation 示例和Monad.

我将主要Either用作我的对类型构造函数,而不是(,)像当前Arrow类那样的类型构造函数。这可能会使我的玩具 RTS 游戏 ( cabal install DefendTheKind) 的代码更漂亮。

4

1 回答 1

20

您需要使用NoImplicitPrelude 扩展来获得完整的可重新绑定语法,包括doand proc。在这种情况下,您会得到以下内容:

“Do”表示法使用范围内的任何函数 (>>=)、(>>) 和失败进行翻译(不是 Prelude 版本)。列表推导、mdo(第 7.3.6 节,“递归 do-notation”)和并行数组推导不受影响。

您还可以调整对否定、相等、文字值等的一些处理。混淆代码的好方法!

ps——如果你要重新绑定do语法,sigfpe 所说的“参数化 monads”非常有趣。Control.Monad.Indexedcategory-extras下也有同样的想法。是的,尽管类型签名完全不同,但它们确实使用可重新绑定的语法!

于 2010-05-13T23:56:34.720 回答