函数得到四个参数而不是三个参数 - 为什么这不中断?



阅读"真实世界Haskell",在第95页,作者提供了一个例子:

myFoldl f z xs = foldr step id xs z
    where step x g a = g (f a x)

我的问题是:为什么要编译这个代码?foldr只接受三个参数,但在这里,它传递了四个参数:stepidxsz

例如,这不起作用(因为sum需要一个):

sum filter odd [1,2,3]

相反,我必须写:

sum $ filter odd [1,2,3]

以下是foldr:的类型

Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b

我们能弄清楚它是如何变成四元函数的吗?让我们试一试吧!

  1. 我们给它id :: d -> d作为第二个参数(b),所以让我们把它代入类型:

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d)
    
  2. 在Haskell中,a -> a -> aa -> (a -> a)相同,后者给出了(去掉最后一组括号):

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d
    
  3. e代替(a -> (d -> d) -> (d -> d)),用f代替(d -> d),使其更易于阅读:

    e -> f -> [a] -> d -> d
    

所以我们可以清楚地看到,我们已经构造了一个四参数函数!我的头很疼。


下面是一个从n-arg函数创建n+1参数函数的简单示例:

Prelude> :t id
id :: a -> a

id是一个自变量的函数。

Prelude> id id id id id 5
5

但我只给了它5个args!

这是因为foldr的多态性:

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

这里,我们已经将b实例化为一个函数类型,我们称之为c -> c,因此foldr的类型专门用于(例如)

foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c

foldr只接受3个参数

错了。Haskell中的所有函数都只接受一个参数,并产生一个结果。

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

请参阅,foldr采用一个参数(a -> b -> b),并产生1个结果:b -> [a] -> b。当你看到这个:

foldr step id xs z

记住,这只是的简写

((((foldr step) id) xs) z)

这就解释了为什么这是无稽之谈:

sum filter odd [1,2,3]
(((sum filter) odd) [1,2,3])

sum :: Num a => [a] -> a将列表作为其输入,但您给了它一个函数。

相关内容

  • 没有找到相关文章

最新更新