Haskell中Church Numerals无限递归类型问题求解
data ChurchN a = ChurchN { numeral :: (a -> a) -> a -> a , litRep :: String } next :: ChurchN a -> ChurchN a next x = ChurchN { numeral = \f y -> f (numeral x f y) , litRep = let (lambx, funct) = splitAt (length "\f x -> ") (litRep x) in lambx ++ "f(" ++ funct ++ ")" } plus :: ChurchN a -> ChurchN a -> ChurchN a plus x y = numeral y next x main :: IO () main = print "hello world" -- this so the code compiles
问题分析与结论
你想通过将next函数应用y次到x上实现加法,但这种直接实现方式在默认Haskell环境下不可行,核心问题出在类型系统的约束:
类型不匹配根源
numeral的类型是(a -> a) -> a -> a,对于y :: ChurchN a,numeral y需要接收的第一个参数是a -> a类型的函数,第二个参数是a类型的值。但你传入的next类型是ChurchN b -> ChurchN b,x是ChurchN b,这要求Haskell推导a = ChurchN b,进而b = ChurchN b,形成无限递归的类型b = ChurchN (ChurchN (ChurchN ...))——这种无限类型是Haskell默认禁止的。强行尝试的局限性
如果开启-XInfiniteTypes扩展并声明无限递归类型,比如type RecursiveChurch = ChurchN RecursiveChurch,可以让类型检查通过,但这种方案实用性极低:- 无限递归类型无法与
Int等常规类型兼容,无法实现Church数到普通整数的转换; - 类型推导会变得复杂,后续扩展功能极易触发新的类型错误。
- 无限递归类型无法与
常规替代实现
如果要保留Church数的泛型特性,加法的标准实现应直接操作numeral的逻辑,避免依赖next的自引用:
plus :: ChurchN a -> ChurchN a -> ChurchN a plus x y = ChurchN { numeral = \f z -> numeral x f (numeral y f z) , litRep = let (lx, fx) = splitAt (length "\f x -> ") (litRep x) (ly, fy) = splitAt (length "\f x -> ") (litRep y) in "\f x -> " ++ fx ++ "(" ++ fy ++ ")" }
这个实现直接组合两个Church数的函数应用逻辑,类型完全合法,且能正常工作。
内容的提问来源于stack exchange,提问作者Raykiru Shiroyshi
相关产品推荐
相关产品推荐

