为什么foldr可以使用三个参数?

时间:2017-07-07 20:06:45

标签: function haskell types arguments fold

我正在查看一些列表操作并遇到!!

(!!)                    :: [a] -> Int -> a
xs !! n
  | n < 0     = negIndex
  | otherwise = foldr (\x r k -> case k of
                                   0 -> x
                                   _ -> r (k-1)) tooLarge xs n

函数(\x r k -> ...)的类型为a -> (Int -> a) -> Int -> a,但foldr采用的函数只能接受两个参数:

foldr            :: (a -> b -> b) -> b -> [a] -> b
foldr k z = go
          where
            go []     = z
            go (y:ys) = y `k` go ys

有人可以向我解释为什么foldr接受一个带有以下类型a -> (Int -> a) -> Int -> a的3个参数的函数?特别是因为结果应该与第二个参数具有相同的类型?

2 个答案:

答案 0 :(得分:2)

->是正确关联的。因此a -> b -> ca -> (b -> c)。因此,您的类型

a -> (Int -> a) ->  Int -> a

相同
a -> (Int -> a) -> (Int -> a)

我们可以看到它很适合foldr的类型。

答案 1 :(得分:1)

(对其他人的更多解释;)

    const expected = [
      { value: "Angle" }, 
      { value: "Mass" }
    ]

(!!) :: [a] -> Int -> a xs !! n | n < 0 = negIndex | otherwise = foldr (\x r k -> case k of 0 -> x _ -> r (k-1)) tooLarge xs n foldr :: (a -> b -> b) -> b -> [a] -> b -- ^1 ^2 通常是一个累积值(?)。在这种情况下,foldr使 类型foldr的累积函数(b)! (Int -> a)被评估为 累积函数,并且此累积函数(foldr ... tooLarge xs)接受参数^2n^1函数。有趣的是, 累积函数取决于自由变量tooLarge(即n)的值。

例如,k的评估如下:
['a', 'b', 'c'] !! 2 = \x r k\'a' r 2 -> r (2-1)尚不为人所知,并推动了进一步的评估。)
r = \x r k
\'b' r 1 -> r (1-1) = \x r k

\'c' r 0 -> 'c'像这样:
['a', 'b', 'c'] !! 3 = \x r k
\'a' r 3 -> r (3-1) = \x r k
\'b' r 2 -> r (2-1) = \x r k\'c' r 1 -> r (1-1)原来是r。)= tooLarge(错误!)

您可以检查调试跟踪:

tooLarge (1-1)


module Main where import Debug.Trace tooLarge _ = errorWithoutStackTrace "!!!: index too large" negIndex = errorWithoutStackTrace "!!!: negative index" (!!!) :: Show a => [a] -> Int -> a xs !!! n | n < 0 = negIndex | otherwise = foldr (\x r k -> trace ("x: " ++ show x ++ ", k: " ++ show k) $ case k of 0 -> x _ -> r (k-1)) tooLarge xs n main = do print $ ['a', 'b', 'c'] !!! 2 print $ ['a', 'b', 'c'] !!! 3 -- x: 'a', k: 2 -- x: 'b', k: 1 -- x: 'c', k: 0 -- 'c' -- x: 'a', k: 3 -- x: 'b', k: 2 -- x: 'c', k: 1 -- sample: !!!: index too large 实现是报告版本。前言的报告版本比熟悉的朴素递归实现更有效, 由于(!!)的优化。