Haskell 为什么类型签名看起来像这样?(将教堂编号转换为整数)

Haskell 为什么类型签名看起来像这样?(将教堂编号转换为整数),haskell,types,type-signature,Haskell,Types,Type Signature,我正在学习Haskell,并试图编写一个函数,将Church数字转换为Int。我的代码只有在不编写类型签名的情况下才能工作 type Church a = (a -> a) -> a -> a zero :: Church a zero s z = z c2i :: Church a -> Int -- This line fails c2i x = x (+1) 0 我使用:t c2i c2i :: (Num a1, Num a) => ((a ->

我正在学习Haskell,并试图编写一个函数,将Church数字转换为Int。我的代码只有在不编写类型签名的情况下才能工作

type Church a = (a -> a) -> a -> a

zero :: Church a
zero s z = z

c2i :: Church a -> Int   -- This line fails
c2i x = x (+1) 0
我使用
:t c2i

c2i :: (Num a1, Num a) => ((a -> a) -> a1 -> t) -> t

但是我想知道为什么会这样?

如果你在
c2i
签名中使用
a
,那么它必须与任何
a
一起工作。 换句话说,
a
由函数的调用者选择。 具体地说,它必须与

c2i :: Church String -> Int
-- that is
c2i :: ((String -> String) -> String -> String) -> Int
由于当
a=String
时代码不起作用,因此多态类型无效

如果不添加类型,编译器可以推断出使代码工作的某种类型。更简单的类型可以是:

c2i :: Church Int -> Int
或者,在启用一些扩展之后

c2i :: (forall a. Church a) -> Int
在后一种情况下,我们指定
a
c2i
选择,而不是由调用方选择。相反,调用者必须传递一个必须具有多态类型的参数:即,它必须为所有
a
传递
Church a
,而不仅仅是
Church字符串

或者,你甚至可以声明

type Church = forall a . (a->a)->a->a

只传递多态性值。

但是
类型
声明会让人很痛苦。相关的