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

And*_*yuk 9 haskell

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

myFoldl f z xs = foldr step id xs z
    where step x g a = g (f a x)
Run Code Online (Sandbox Code Playgroud)

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

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

sum filter odd [1,2,3]
Run Code Online (Sandbox Code Playgroud)

相反,我必须写:

sum $ filter odd [1,2,3]
Run Code Online (Sandbox Code Playgroud)

Mat*_*ick 12

这是以下类型foldr:

Prelude> :t foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
Run Code Online (Sandbox Code Playgroud)

我们能弄清楚它是如何成为一个四参数函​​数的吗?试一试吧!

  1. 我们将它id :: d -> d作为第二个参数(b),所以让我们将其替换为类型:

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> (d -> d)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在Haskell中,a -> a -> a它是相同的a -> (a -> a),它给了我们(删除最后一组括号):

    (a -> (d -> d) -> (d -> d)) -> (d -> d) -> [a] -> d -> d
    
    Run Code Online (Sandbox Code Playgroud)
  3. 让我们简化,通过置换e(a -> (d -> d) -> (d -> d))f(d -> d),使之更易于阅读:

    e -> f -> [a] -> d -> d
    
    Run Code Online (Sandbox Code Playgroud)

所以我们可以清楚地看到我们已经构建了一个四参数函​​数!我头疼.


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

Prelude> :t id
id :: a -> a
Run Code Online (Sandbox Code Playgroud)

id 是一个参数的函数.

Prelude> id id id id id 5
5
Run Code Online (Sandbox Code Playgroud)

但我刚给它5个args!

  • @drozzy - 它是关于类型和多态的.把`id :: a - > a`:你可以用*any*替换为'a`.但是,`foo`是不同的,因为它有约束:它需要一个数字:`foo ::(Num a)=> a - > a`.`bar ::(Num a)=> a - > a`不是`Num`类型类的实例,因此不满足``foo`的`(Num a)`约束. (4认同)
  • @drozzy如果我们澄清功能应用的相关性,也许会有所帮助!请记住,`id id 5`解析为`(id id)5` - 也就是说,首先将`id`作为参数提供给`id`,然后将`5`作为结果的参数 - 而不是`` id(id 5)`. (2认同)

Dan*_*ner 10

这是因为多态性foldr是多少:

foldr :: (a -> b -> b) -> b -> [a] -> b
Run Code Online (Sandbox Code Playgroud)

在这里,我们已经实例化为b一个函数类型,让我们调用它c -> c,所以foldr专门的类型(例如)

foldr :: (a -> (c -> c) -> (c -> c)) -> (c -> c) -> [a] -> c -> c
Run Code Online (Sandbox Code Playgroud)


Dan*_*ton 9

foldr 只需要3个参数

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

foldr :: (a -> b -> b) -> b -> [a] -> b
Run Code Online (Sandbox Code Playgroud)

看,foldr拿一个参数(a -> b -> b),产生1个结果:b -> [a] -> b.当你看到这个:

foldr step id xs z
Run Code Online (Sandbox Code Playgroud)

请记住,这只是简写:

((((foldr step) id) xs) z)
Run Code Online (Sandbox Code Playgroud)

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

sum filter odd [1,2,3]
(((sum filter) odd) [1,2,3])
Run Code Online (Sandbox Code Playgroud)

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