为什么Haskell中的这两个函数具有相同的类型?

时间:2011-11-22 11:23:54

标签: function haskell types

我正在通过Graham Hutton的在Haskell编程,第3章的练习问“什么是类型?”对于函数twice f x = f (f x)

我想我理解为什么答案是twice :: (t -> t) -> t -> t。 (编辑:我做了了解原因。请参阅我对Paolo答案的评论。)但是,为了实验我写了另一个函数thrice f x = f (f (f x))

我绝对不会理解的是thrice也有thrice :: (t -> t) -> t -> t类型的原因。

他们按照我期望的方式工作(见下文),但我看不出thrice的类型是否有意义。

来自ghci

>> twice tail [0,1,2,3,4]
[2,3,4]
>> thrice tail [0,1,2,3,4]
[3,4]

4 个答案:

答案 0 :(得分:8)

也许更容易看到无点:

twice f = f . f
thrice f = f . f . f

所以你自己组合f几次。为了能够将f与自身组合在一起,将f应用于参数的结果必须具有合适的类型,以便f可以应用于此。现在,如果你从

开始
f :: a -> r     -- argument type -> result type

适用性条件意味着r必须与a匹配。对于表示r = a的类型变量。因此,twice以及thrice将函数从某种类型转换为相同类型,并将函数从该类型返回到相同类型,

twice :: (a -> a) -> (a -> a)
thrice :: (a -> a) -> (a -> a)

由于函数类型箭头是右关联的(x -> y -> z = x -> (y -> z)),因此可以省略类型中的最后一个括号。

答案 1 :(得分:4)

抱歉,也许我不明白你的问题,但是如果你看一下你自己的列表示例,你会看到在两次和三次的情况下,输入是从列表到列表的函数({{1 }}和一个列表(tail),返回类型是一个列表。

因此[0,1,2,3,4]twice都匹配签名thrice:从t到t的函数(在您的情况下为(t -> t) -> t -> t),在(在您的情况下是一个列表)和另一个t(列表)作为回报

答案 2 :(得分:4)

两次的类型表明两次是来自具有域 a 和codomain a 的函数的函数到域 a 和codomain a 的函数。 三次的类型表明三次是来自具有域 a 和codomain a 到函数的函数的函数域 a 和codomain a

要了解原因,请考虑推导两次三次的类型。给定函数 f a a 和变量 x ,确定类型的规则f fx )声明我们必须首先确定 f (fx)的类型,然后应用规则功能应用。确定(fx)类型的规则规定我们必须首先确定 f x 的类型,然后应用规则进行功能应用

首先,因为 f 的类型为 a a x 的类型为 a ,函数应用程序的规则指出( fx )的类型为 a 。由于 f 的类型为 a a ,( fx )的类型为 a ,函数应用程序的规则指出 f fx )的类型为 a 。函数应用程序规则的另一个应用是 f f f x ))类型 a 。如您所见,为应用程序重复应用规则, f n x 将为所有<的 a 类型< em> n ∈ℕ。

其次,函数抽象规则指出,如果 x τ M τ' x M 中不会自由发生,然后抽象λ x τ M 的类型为ττ'。我们有术语 f fx )和 f f fx ))类型为 a 的变量和类型为 a 的变量 x 。因此,抽象λ x a f f x )和λ x a f f f x ))都有类型 a a 。最后,由于 f a a ,再次应用函数抽象规则得到λ f :< em> a → a 。 λ x a f f x )和λ f a a 。 λ x a f f fx ))具有类型( a a )→ ( a a )。

正如您所看到的,Haskell的类型系统过于无法表达两次将函数 f 应用于参数 x 两次,而三次将函数 f 应用于参数 x 三次。 可以表达的是两次三次接受函数作为输入并从术语 x 到术语 y ,类型 a 。此函数是λ x a f f x 两次和λ x a f f f x ))三次

我建议阅读Haskell类型系统所基于的多态性λ演算的简短介绍。这将呈现打字关系,并且可能引导读者证明某些术语具有某些类型。

答案 3 :(得分:1)

试图赢得简洁比赛:

类型签名指定函数的输入(参数)的类型,以及函数返回的值 因此,函数类型签名中的项目数是(n + 1),其中n是函数所用参数的数量。