【问题标题】:Couldy you help me understand the type of an implementation of foldr in Haskell?你能帮我理解 Haskell 中 foldr 的实现类型吗?
【发布时间】:2020-12-16 09:23:00
【问题描述】:

在标题为“Haskell 编程”的书中,第 77 页,有一个 foldr 的实现,以解释该功能。它看起来像这样:

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f v [] = v
foldr f v (x:xs) = f x (foldr f v xs)

为什么不是这样的类型:

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

第一个参数,它是一个函数(a -> b -> b),将始终应用于列表的头部,以及递归处理的尾部。

但是有什么例子,头部和递归处理的尾部最终具有不同的类型?

我肯定不明白这里的一些东西。你能分解一下为这个 foldr 实现编写类型的过程吗?

【问题讨论】:

  • foldr (:) [] 是一个简单的例子。这里你构造一个列表,所以这里是b ~ [a]
  • 请注意,第二个参数是在列表尾部递归的结果,因此它也是b
  • "但是有什么例子,头部和递归处理的尾部最终具有不同的类型?"。如果头部和递归处理的尾部总是具有相同的类型,则签名将归结为foldr :: (a -> a -> a) -> a -> [a] -> a,因为在这种情况下,“折叠函数”不能返回a不同的东西,因此 foldr 的输出类型也应该是 a
  • this question 上的现有答案也可能会有所帮助。

标签: haskell


【解决方案1】:

请注意,在每个点处,传递函数的尾部都是递归调用foldr 的结果。由于foldr 返回类型b,因此函数类型为a -> b -> b 是有意义的:它的第一个参数是头部,第二个参数是递归foldr 调用的结果。

此外,基本情况是b 类型,因为foldr 调用[] 只是返回基本情况。


手动扩展 foldr 评估的具体示例(来自 Willem 的 cmets 问题)可能会有所帮助。

例如,

  foldr (:) [] [1,2,3]
= (:) 1 (foldr (:) [] [2,3])
= (:) 1 ((:) 2 (foldr (:) [] [3]))
= (:) 1 ((:) 2 ((:) 3 (foldr (:) [] [])))
= (:) 1 ((:) 2 ((:) 3 [])) -- base case used here
= (:) 1 ((:) 2 [3])
= (:) 1 [2,3]
= [1,2,3]

这里,应用于头部和尾部的函数是Int -> [Int] -> [Int]类型,意思是a = Intb = [Int]

旁注:foldr (:) [] = id 确实如此。

【讨论】:

  • 你说得对——我搞砸了,因为我有一个更复杂的函数,为了简单起见,我将它编辑到 (++) 中,但没有进行相应的调整。我会立即用一个更好的例子来替换它!
【解决方案2】:

您可以将b 视为计算状态,而将a 视为输入数据。您向后遍历列表并对顺序输入a 类型)做出反应。要描述这个计算,你需要 3 件事:

  • 一种在新的输入 (a) 上更新状态b 类型)的方法。因此,您需要一个接受输入先前状态并产生新状态的函数:a -> b -> b
  • 一些初始状态(ofc,b
  • 输入/事件的序列——在本例中是as 的列表。

重写foldr的类型可能更清楚,以显示每种类型的用途:

foldr :: (input -> state -> state) -> state -> [input] -> state
foldr update initialState inputs = case inputs of
  []  -- no inputs, so we leave it as it was
    -> initialState
  (input : rest) ->
    let -- update state on all of the other inputs
        prevState = foldr update initialState rest
        -- update state on the current input
        newState = update input prevState
    in newState

foldl tho 上更容易看到此流程。那么在foldr中,遍历的顺序正好相反。

【讨论】:

    猜你喜欢
    • 2021-06-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 1970-01-01
    • 2021-04-15
    • 2011-04-02
    • 2012-06-05
    • 2014-10-13
    相关资源
    最近更新 更多