要求GHC打印“一”和“ succ零”(编码数字的lambda微积分方式)的类型,我得到两种不同的类型! 他们不应该一样吗? 您还能告诉我如何手动导出其类型吗?
zero = \ f x -> x
one = \ f x -> f x
succ = \ n f x -> f (n (f x))
:t one -- (t1 -> t2) -> t1 -> t2
:t succ zero -- ((t1 -> t1) -> t2) -> (t1 -> t1) -> t2
答案 0 :(得分:4)
正如评论中所说,正确的定义是
zero f x = x
succ n f x = f (n f x)
“从
f
开始,在n
的{{1}}应用后再进行一次f
。”
因此
x
最初得到的类型更普遍,
one f x = succ zero f x = f (zero f x) = f x
two f x = succ one f x = f (one f x) = f (f x)
但这并不重要,它们之间都相互匹配(统一),并且从zero :: t -> t1 -> t1 -- most general
one :: (t1 -> t ) -> t1 -> t -- less general
succ one :: (t2 -> t2) -> t2 -> t2 -- most specific
开始,类型便确定为最具体的two = succ one
。
您也可以定义
(b -> b) -> (b -> b)
且所有类型都与
完全相同church :: Int -> (b -> b) -> b -> b -- is derived so by GHCi
church n f x = foldr ($) x (replicate n f)
= foldr (.) id (replicate n f) x
{- church n = foldr (.) id . replicate n -- (^ n) for functions -}
这没关系。
关于类型派生,归结为仅使用了模式/应用规则
church 0 :: (b -> b) -> b -> b
church 1 :: (b -> b) -> b -> b
church 2 :: (b -> b) -> b -> b
只需小心地一致地重命名每种类型,以便在任何步骤都不会引入类型变量:
f :: a -> b
x :: a
-------------
f x :: b
(因为 succ n f x = f (n f x)
x :: a
f :: t , t ~ ...
n :: t -> a -> b
f :: b -> c , t ~ b -> c
succ n f x :: c
succ :: (t -> a -> b) -> (b -> c) -> a -> c
:: ((b -> c) -> a -> b) -> (b -> c) -> a -> c
产生的最终结果类型与succ
产生的最终结果类型相同-即f
),或者按照GHCi的说法,
c
答案 1 :(得分:2)
首先,您希望zero
与one
具有相同的类型。在zero
的等式中,不要在f
的rhs上使用->
。因此,编译器不知道要推断的类型。在one
的方程式中,您希望f x
(其结果)与x
(zero
的结果)具有相同的类型。但是你也没有得到。给出签名最简单,但是如果失败,则使用asTypeOf
。
在succ
的方程式中,您希望其结果与f x
相同,并且与x
相同。
您还可以教我如何手动导出其类型吗?
好的,让我们使用asTypeOf
完成以上操作。然后,您可以使用:t
查找类型...
zero = \ f x -> (x `asTypeOf` f x)
one = \ f x -> (f x `asTypeOf` x)
succ = \ n f x -> (f (n f x)
`asTypeOf` f x `asTypeOf` x)
(每个@LambdaFairy我已经为succ
使用了正确的定义。)
请注意,教堂数字被用无类型的lambda演算框起来-这就是维基百科所显示的内容。当您了解更多关于它们的奇异函数(例如加法或前代)时,您会发现Haskell是类型化的lambda演算,而GHC会阻碍/您将达到可怕的单态性限制。然后asTypeOf
无法帮助您;您必须使用(高级)类型签名。