do 符号是否特定于“base:GHC.Base.Monad”?
题
标准的想法 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 扩展 完整的可重新绑定语法,包括 do
和 proc
. 。在这种情况下,您会得到以下信息以及其他信息:
“Do”符号使用范围内的任何函数 (>>=)、(>>) 和失败进行翻译(不是 Prelude 版本)。列表推导式、mdo(第 7.3.6 节,“递归 do 表示法”)和并行数组推导式不受影响。
您还可以调整对否定、相等、文字值等的一些处理。混淆代码的好方法!
附注-- 如果您要重新绑定 do
句法, sigfpe 称之为“参数化 monad” 非常有趣。同样的想法可以在 category-extras
在下面 控制单子索引. 。是的,尽管类型签名截然不同,但它们确实可以使用可重新绑定的语法!
不隶属于 StackOverflow