基于MonadAff泛化PureScript函数遇类型错误求解
理解并解决PureScript中MonadAff泛化的Kind不匹配错误
首先,咱们得把你遇到的错误根源拆解清楚——这本质是对MonadAff类型类的**kind(类型的类型)**理解偏差导致的,我来一步步给你捋明白。
先搞懂MonadAff的类型签名
PureScript里MonadAff的核心定义是这样的:
class (Monad m, MonadEffect m) <= MonadAff (e :: # Effect) m | m -> e where -- 类方法实现...
这里有两个关键细节你得记牢:
e的kind是# Effect:它是一个Effect行类型,用来描述这个monad能支持的副作用集合m的kind是Type -> Type:它是标准的单参数monad构造器(比如Aff本身是# Effect -> Type -> Type,但当我们用MonadAff e m约束时,m已经是绑定了特定e的单参数构造器,比如Aff e)
你的错误到底出在哪
你写的类型声明MonadAff e m => m e Int犯了两个关键错误:
m是Type -> Type的构造器,它只能接受一个Type类型的参数,但你硬塞了两个:e(属于# Effectkind,不是Type)和Int(Type)MonadAff e m已经通过函数依赖m -> e把m和对应的effect行e绑定死了,你根本不需要再把e当成m的参数传递
编译器报的“无法匹配kind type与kind # Control.Monad.Eff.Effect”,就是因为它期望m的参数是Type类型,但你传了一个Effect行类型,两者的“类型的类型”不匹配,自然报错。
正确的泛化写法
假设你的初始函数是类似这样的:
testOriginal :: Aff (err :: Error) Int testOriginal = pure 42
如果要基于MonadAff做泛化,正确的类型应该写成:
test3 :: MonadAff e m => m Int test3 = pure 42
这里的逻辑是:
MonadAff e m约束保证m是一个支持Aff操作的monad,并且已经关联了对应的effect行em Int是合法的返回类型:m作为Type -> Type构造器,只需要接受Int这个Type参数,就能返回一个monadic值
关于你提到的Hyper.Node中的类似示例
你说在Hyper.Node相关代码里见过类似泛化,大概率是混淆了MonadAff的effect行e和MonadError的错误类型参数。比如你可能看到的是结合MonadError的泛化写法:
testWithError :: (MonadAff e m, MonadError MyError m) => m Int testWithError = throwError MyError <|> pure 42
这里的e(Effect行,# Effect kind)和MyError(错误类型,Type kind)是完全不同的参数,可别把它们混为一谈哦。
总结一下:MonadAff的e是用来描述副作用的行类型,不是monad的参数,泛化时只需要声明MonadAff e m约束,然后返回m Int就可以了。
内容的提问来源于stack exchange,提问作者Joop Ringelberg
相关产品推荐
相关产品推荐

