Haskell中含列表构造器的`a`和类型为何不匹配`a`的列表?
解决原始递归组合函数的类型不匹配问题
你的核心问题是没有把普通列表包装成PrimT类型,导致编译器无法匹配函数f的参数类型。让我一步步拆解:
错误原因分析
看你定义的o函数类型:
o :: PrimT (PrimT b -> PrimT c) -> PrimT (PrimT a -> PrimT b) -> PrimT a -> PrimT c
其中Sgl f里的f类型是PrimT b -> PrimT c——它要求传入一个PrimT b类型的值(要么是Sgl包裹的单个值,要么是Sqc包裹的列表)。但你写的[g args | g <- gs]生成的是普通Haskell列表[PrimT b],并没有用PrimT的构造器包裹,这俩类型完全不兼容,编译器自然报错。
修正后的代码
针对你设计的四个组合场景,我们只需要把生成的结果用对应的PrimT构造器包装即可:
o :: PrimT (PrimT b -> PrimT c) -> PrimT (PrimT a -> PrimT b) -> PrimT a -> PrimT c -- 场景1:单个函数 + 函数列表 + 参数列表 o (Sgl f) (Sqc gs) (Sqc args) = f $ Sqc [g args | g <- gs] -- 场景2:单个函数 + 函数列表 + 单个参数 o (Sgl f) (Sqc gs) (Sgl arg) = f $ Sqc [g arg | g <- gs] -- 场景3:单个函数 + 单个函数 + 参数列表 o (Sgl f) (Sgl g) (Sqc args) = f $ g args -- 场景4:单个函数 + 单个函数 + 单个参数 o (Sgl f) (Sgl g) (Sgl arg) = f $ g arg
关键细节说明
- 对于函数列表的场景(1、2):多个
g的执行结果会被收集成普通列表,我们用Sqc把它包裹成PrimT b类型,这样才能满足f的参数要求。 - 对于单个函数的场景(3、4):
g的执行结果本身就是PrimT b类型,直接传给f即可,不需要额外包装。
另外提一句:你的zero和pi返回的是Either String Int,但nu返回的是PrimT Int,这里类型有点不一致,后续可能需要统一成Either String (PrimT Int)来处理错误情况,不过这是另一个优化方向了。
内容的提问来源于stack exchange,提问作者lo tolmencre
相关产品推荐
相关产品推荐

