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

Haskell嵌套应用函子时让QualifiedDo与ApplicativeDo协同工作的方案

报错原因

开启ApplicativeDo扩展后,GHC会自动将do块语法重写为pure Foo <$> someConfigurator <*> someAllocator的Applicative风格调用,你自定义的Bind模块中<*>的实现逻辑是每次调用都新增一层Compose包装,和预先定义的左结合多层Compose类型Phases结构不匹配,因此触发类型错误。


解决方案

方案一(最简便,无需修改Bind模块)

在用到Bind.do的位置局部关闭ApplicativeDo扩展,不影响模块其他位置的ApplicativeDo使用:

{-# LANGUAGE QualifiedDo #-}
{-# LANGUAGE ApplicativeDo #-}
import qualified Bind

fooPhases :: Phases Foo
fooPhases = 
  let {-# LANGUAGE NoApplicativeDo #-} 
  in Bind.do 
    i <- someConfigurator 
    c <- someAllocator 
    pure (Foo i c)

该方案下GHC不会对目标do块做Applicative重写,仍然使用你原本定义的>>=逻辑,可正常编译运行。


方案二(完全适配ApplicativeDo重写逻辑)

修改Bind模块,通过类型类和类型族自动匹配多层Compose的堆叠结构:

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE OverlappingInstances #-}
module Bind where
import Data.Functor
import Data.Functor.Compose
import Prelude hiding ((>>=), (>>), fail, return, pure, fmap, (<*>))

-- 原有绑定逻辑保持不变
(>>=) :: Functor f => f a -> (a -> g b) -> Compose f g b 
(>>=) f k = Compose (f <&> k)

(>>) :: Functor f => f a -> g b -> Compose f g b 
(>>) f g = Compose $ f <&> \_ -> g

fail :: MonadFail m => String -> m a
fail = Prelude.fail

-- 类型族计算多层Compose堆叠后的结果类型
type family ComposeStack f g where
  ComposeStack (Compose f g) h = Compose f (Compose g h)
  ComposeStack f g = Compose f g

-- 重载<*>适配不同层级的Compose
class ApplicativeApply f g where
  (<*>) :: f (a -> b) -> g a -> ComposeStack f g b

instance {-# OVERLAPS #-} (Applicative f, Applicative g, Applicative h) => ApplicativeApply (Compose f g) h where
  (<*>) (Compose fgh) ha = Compose $ fmap Compose $ fgh <&> \gh -> gh <*> ha

instance (Applicative f, Applicative g) => ApplicativeApply f g where
  (<*>) fg ga = Compose $ fmap ($ ga) fg

-- 其余通用操作保持适配
fmap :: Functor f => (a -> b) -> f a -> f b
fmap = Prelude.fmap

pure :: Applicative f => a -> f a
pure = Prelude.pure

return :: Applicative f => a -> f a
return = Prelude.pure

修改后即使全局开启ApplicativeDo也可以正常编译运行。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 23:30:00