You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在GHC 7.10及更高版本中为自定义类型实现Monad

为WhoCares类型实现Monad实例

《Haskell Programming from First Principles》中提到:
若使用GHC 7.10或更高版本,你会看到Monad的定义中包含Applicative约束,这是合理的:

class Applicative m => Monad m where
    (>>=) :: m a -> (a -> m b) -> m b
    (>>) :: m a -> m b -> m b
    return :: a -> m a

我已经实现了WhoCares类型的Functor和Applicative实例:

data WhoCares a = ItDoesnt | Matter a | WhatThisIsCalled deriving (Eq, Show)

instance Functor WhoCares where
    fmap _ ItDoesnt = ItDoesnt
    fmap _ WhatThisIsCalled = WhatThisIsCalled
    fmap f (Matter a) = Matter (f a)

instance Applicative WhoCares where
    pure = Matter
    Matter f <*> Matter a = Matter (f a)

但我不清楚如何为该类型实现>>=和>>方法,目前尝试的代码存在错误:

instance Monad (WhoCares a) where
    (>>=) :: Matter a -> (a -> Matter b) -> Matter b
    (>>) :: Matter a -> Matter b -> Matter b
    return :: a -> Matter a
    return = pure

期望的用法与输出

我希望实现后能支持以下测试代码,并得到对应输出:

测试代码

half x = if even x
            then Matter (x `div` 2)
            else ItDoesnt

incVal :: (Ord a, Num a) => a -> WhoCares a
incVal x
    | x + 1 <= 10 = return (x + 1)
    | otherwise = ItDoesnt

decVal :: (Ord a, Num a) => a -> WhoCares a
decVal x
    | x - 1 >= 0 = return (x - 1)
    | otherwise = ItDoesnt

main = do
    print (Matter 7 >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal)
    print (Matter 7 >>= incVal >>= incVal >>= incVal >>= incVal >>= decVal >>= decVal)
    print (Matter 2 >>= decVal >>= decVal >>= decVal)
    print(Matter 20 >>= half >>= half)

预期输出

Matter 10
ItDoesnt
ItDoesnt
ItDoesnt
Matter 5

正确的Monad实例实现

你的代码存在两个核心问题:

  1. 实例声明错误:instance Monad (WhoCares a)是具体类型的写法,Monad实例需要针对类型构造器声明,即instance Monad WhoCares
  2. 未处理所有构造器:>>=和>>需要覆盖WhoCares的所有三种情况(ItDoesnt、Matter、WhatThisIsCalled)

完整的正确实现如下:

instance Monad WhoCares where
    return = pure  -- 复用Applicative的pure,语义一致
    
    -- 绑定操作>>=的实现
    ItDoesnt >>= _ = ItDoesnt
    WhatThisIsCalled >>= _ = WhatThisIsCalled
    Matter a >>= f = f a
    
    -- 序列操作>>的实现(可选,不定义则使用默认实现:x >> y = x >>= \_ -> y)
    ItDoesnt >> _ = ItDoesnt
    WhatThisIsCalled >> _ = WhatThisIsCalled
    Matter _ >> y = y

逻辑说明

  1. return:直接复用Applicative的pure,因为Monad的return和Applicative的pure都是将普通值包装到类型构造器中。
  2. >>=(绑定):
    • 若当前值是ItDoesnt或WhatThisIsCalled,直接返回自身,不执行后续函数,符合“失败即终止”的语义
    • 若当前值是Matter a,则将a传入函数f,返回f a的结果,这是Monad绑定的核心逻辑
  3. >>(序列):
    • 非Matter构造器直接返回自身
    • Matter构造器忽略自身值,返回第二个参数,和默认实现逻辑一致

现在运行测试代码,就能得到预期的输出结果。

内容的提问来源于stack exchange,提问作者Ahmad Ismail

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:30:52