2012-02-11 65 views
9

读“真实世界哈斯克尔”,95页的作者提供了一个例子:函数获取四个参数而不是三个 - 为什么不打破?

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

我的问题是:为什么这个代码编译? foldr只需要三个参数 - 但在这里,它通过四个:step,id,xs,z

例如,这不起作用(因为总和预计一个):

sum filter odd [1,2,3] 

相反,我必须写:

sum $ filter odd [1,2,3] 

回答

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 -> a相同a -> (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 FUNC创建的n + 1参数的功能的一个简单的例子:

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

id是一个参数的函数。

Prelude> id id id id id 5 
5 

但我刚给了它5个参数!

+0

我不明白你为什么可以做'id id 5',但是你不能这样做:'foo x = x + 1;条y = y + 1; foo bar 1'? – drozzy 2012-02-11 23:46:32

+4

@drozzy - 这一切都是关于类型和多态的。以'id :: a - > a':你可以用* any替换'a'。然而,'foo'是不同的,因为它有约束:它需要一个数字:'foo ::(Num a)=> a - > a'。 'bar ::(Num a)=> a - > a'不是'Num'类型类型的实例,因此不符合'foo'的'(Num a)'约束。 – 2012-02-11 23:51:03

+2

@drozzy如果我们澄清函数应用程序的关联性,也许会有所帮助!请记住'id id 5'解析为'(id id)5' - 也就是说,首先将'id'作为'id'的参数,然后将'5'作为结果的参数 - 而不是' id(id 5)'。 – 2012-02-12 01:26:09

10

这是因为foldr如何多态是:

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

在这里,我们已经将b实例化为一个函数类型,我们称之为c -> c,所以foldr类型专门到(例如)

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

你也可以指出原始问题中的中性元素已经是一个函数'id'。 – ShiDoiSi 2012-02-11 20:53:03

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将列表作为其输入,但你给了它一个功能。

相关问题