【问题标题】:How many arguments takes the foldr function of Haskell?Haskell 的 foldr 函数有多少个参数?
【发布时间】:2011-01-19 08:06:24
【问题描述】:

我是 Haskell 的新手,我正在阅读这本书 "Real World Haskell"。在本书的第 4 章中,作者要求作为练习使用 fold 重写 groupBy 函数。该书的一位读者(Octavian Voicu)给出了以下解决方案:


theCoolGroupBy :: (a -> a -> Bool) -> [a] -> [[a]]
theCoolGroupBy eq xs = tail $ foldr step (\_ -> [[]]) xs $ (\_ -> False)
                       where step x acc = \p -> if p x then rest p else []:rest (eq x)
                                          where rest q = let y:ys = acc q in (x:y):ys

我的问题很简单: 我知道 foldr 需要 3 个参数:一个函数、一个初始值和一个列表。但在代码的第二行中,foldr 需要 4 个参数。 为什么会这样? 谢谢。

【问题讨论】:

    标签: function haskell arguments fold


    【解决方案1】:

    这种情况,我觉得最好看foldr的类型签名:

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

    并将其与我们拥有的表达式匹配(为清楚起见添加了括号):

    (foldr step (\_ -> [[]]) xs) (\_ -> False)
    

    foldr 的第二个参数与其结果的类型相同。在这种情况下,第二个参数是一个函数。在这种情况下,这意味着带有 3 个参数的 foldr 表达式将是一个函数。

    你看到的 foldr 函数的第四个参数也可以被认为是 foldr 结果的第一个参数!

    【讨论】:

      【解决方案2】:

      Haskell 中的所有函数都只接受一个参数。当我们有一个类型为a -> b -> c 的函数时,它只是写a -> (b -> c) 的一种更短的方式,即一个函数,它接受一个参数并产生一个接受另一个参数的函数。请参阅Currying 了解更多信息。

      在这种情况下,请参阅@sepp2k 的答案。 foldr 产生一个函数,它需要另一个(“第四个”)参数。

      【讨论】:

        【解决方案3】:

        在这种情况下,foldr 用于构建函数。 (\_ -> False) 是该函数的参数。

        【讨论】:

          【解决方案4】:

          Scott 的回答是正确的,foldr 的结果是一个函数,所以这就是为什么foldr 似乎需要 4 个参数。 foldr 函数确实需要 3 个参数(函数、基数、列表):

          *Main> :type foldr
          foldr :: (a -> b -> b) -> b -> [a] -> b
          

          我在这里只举一个不太复杂的例子:

          inc :: Int -> (Int -> Int)
          inc v = \x -> x + v
          
          test = inc 2 40  -- output of test is 42
          

          在上面的代码中,inc 接受一个参数v,并返回一个函数,该函数将其参数增加v

          如下所示,inc 2 的返回类型是一个函数,所以它的参数可以简单地添加到末尾:

          *Main> :type inc
          inc :: Int -> Int -> Int
          *Main> :type inc 2
          inc 2 :: Int -> Int
          *Main> :type inc 2 40                                                        
          inc 2 40 :: Int
          

          括号可以用来强调返回值是一个函数,但功能上和上面的代码是一样的:

          *Main> (inc 2) 40
          42
          

          PS:我是原评论的作者:)

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-12-21
            • 2013-01-11
            • 1970-01-01
            • 1970-01-01
            • 2022-01-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多