我试图推断出类型:
((.) 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的输入。为什么在应用组合仿函数后,您可以使用部分应用程序?对此有规定吗? 此外,我想如果有人确认或否认"非贪婪"类型匹配..
答案 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:
为什么我无法删除原始折叠器中的那些
同样的原因。