标准的想法 Monad 类是有缺陷的,它实际上应该扩展 Functor 或者 Pointed 漂浮在周围。

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

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 表示法时:

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 表示法仅适用于 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的过程符号与我的 Arrow 类,但这会失败,就像上面的 do-notation 示例一样 Monad.

我主要会用 Either 作为我的配对类型构造函数而不是 (,) 类型构造函数与当前类型一样 Arrow 班级。这可能允许制作我的玩具 RTS 游戏的代码(cabal install DefendTheKind)更漂亮了。

有帮助吗?

解决方案

您需要使用 NoImplicitPrelude 扩展 完整的可重新绑定语法,包括 doproc. 。在这种情况下,您会得到以下信息以及其他信息:

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

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

附注-- 如果您要重新绑定 do 句法, sigfpe 称之为“参数化 monad” 非常有趣。同样的想法可以在 category-extras 在下面 控制单子索引. 。是的,尽管类型签名截然不同,但它们确实可以使用可重新绑定的语法!

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top