输入函数Haskell的推断

时间:2014-05-13 14:57:11

标签: function haskell types

我试图推断出类型:

((.) foldr)

i手动推断的类型与ghci推断的不同。这就是我的所作所为:

(.) ::    ( b  ->    c) -> (a->b)->a->c
foldr:: (a'->b'->b')->b'->[a']->b'

现在我的第一个怀疑。 Foldr必须与b-> c进行统一.c foldr必须与(b-> c)统一,但实现它的方法不止一种;像

b ~ (a'->b'->b')
c ~ b'->[a']->b'

或..

b ~ (a'->b'->b')b'->[a']
c ~ b'

我怎么知道该拿哪个?

在ghci中做了不同的例子我得出的结论是,haskell试图以非贪婪的方式为第一个参数统一类型(这个结论完全是实验性的,可能是完全错误的,也许是我到达错误类型的原因对于函数,但是我想到的类型推论我试过haskell)。因此,假设这是真的,配置haskell尝试首先统一是:

b ~ (a'->b'->b')
c ~ b'->[a']->b'

所以现在......

(.)foldr :: (a->b)->a->c

代替b和c:

    (.)foldr :: (a-> (a'->b'->b') )->a->b'->[a']->b' 

哪个足够接近我唯一的问题是表达式中的括号 (一个' - > B' - > B&#39) 当你无法删除原始折叠器中的那些时,为什么我可以删除它们,并且该功能将成为foldr的输入。为什么在应用组合仿函数后,您可以使用部分应用程序?对此有规定吗? 此外,我想如果有人确认或否认"非贪婪"类型匹配..

2 个答案:

答案 0 :(得分:4)

->

的关联性

在Haskell中,唯一的函数类型是a -> b,它是一个带a和“返回”b的函数。因此,函数类型为:

a -> b -> c

隐含地:

a -> (b -> c)

这是一个函数,它接受a并返回一个带b并返回c的函数。您只需要记住->right associative。这是允许currying的“机制”。

答案

  

我怎么知道该拿哪个?

所以,在你的例子中:

foldr:: (a' -> b' -> b') -> b' -> [a'] -> b'

变为:

foldr:: (a' -> b' -> b') -> (b' -> ([a'] -> b'))

正如您所看到的,推断类型a -> b的唯一方法是将(a'->b'->b')分配给a,将(b'->([a']->b'))分配给b


  

为什么我无法删除原始折叠器中的那些,并且该功能将成为foldr的输入?

因为在函数组合之后,类型是:

(a -> (a' -> b' -> b')) -> a -> b' -> [a'] -> b'
-- ^^^^^^^^^^^^^^^^^^^^

让我们关注第一部分:

(a -> (a' -> b' -> b'))

这是因为->的正确关联性,等于:

(a -> (a' -> (b' -> b')))

也等于:

(a -> a' -> b' -> b')

用于相同的关联规则。


  

为什么在应用合成仿函数后,您可以使用部分应用程序?对此有规定吗?

当一个函数占用超过1个“参数”时,可以始终应用部分应用程序(或者更准确地说,当你有一个返回函数的函数时)。

答案 1 :(得分:2)

在类型签名中,(->)是右关联的,这意味着

a -> b -> c

这是一个函数的类型,它接受类型为a的参数并返回另一个类型为b -> c的函数,等于

a -> (b -> c)

但是,它不等于

(a -> b) -> c

这是一个函数的类型,它将另一个类型为a -> b的函数作为其唯一参数,并返回类型为c的值。

问题1:

  

我怎么知道该拿哪个?

您应该选择第一个版本,因为

(a'->b'->b')->b'->[a']->b'

等于

(a'->b'->b')->(b'->[a']->b')

这称为currying,而不是贪婪。

问题2:

  

为什么我无法删除原始折叠器中的那些

同样的原因。