函数得到四个参数而不是三个 - 为什么不打破?

时间:2012-02-11 20:45:34

标签: haskell

阅读“真实世界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]

3 个答案:

答案 0 :(得分:12)

以下是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
    
  4. 所以我们可以清楚地看到我们已经构建了一个四参数函​​数!我的头疼。


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

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

    id是一个参数的函数。

    Prelude> id id id id id 5
    5
    

    但我只给了5个args!

答案 1 :(得分:10)

这是因为多态foldr是多少:

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

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

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

答案 2 :(得分:9)

  

foldr只需要3个参数

错误。 Haskell中的所有函数都只取1个参数,并产生1个结果。

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以列表作为输入,但是你给了它一个函数。