Haskell 了解foldr和Unfover的工作
我很难理解这些代码是如何工作的 “映射”函数必须将该函数应用于给定列表中的所有元素,并生成包含应用结果的列表。所以我们给出了函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“x”和尾“xs”,我们将函数“f”应用于x,并将其附加到“xs”。但是接下来会发生什么呢?foldr的第二个参数(通常必须是某个起始值)的具体方式和内容。空名单的目的是什么? 函数“rangeTo”:我们正在创建lambda表达式,其中我们正在检查是否超出范围,如果超出范围,则结束,如果不在末尾,则给出一对,其中第一个数字附加到结果列表中,第二个数字用作“from”的下一个值。这就是函数中发生的一切,还是我遗漏了什么Haskell 了解foldr和Unfover的工作,haskell,Haskell,我很难理解这些代码是如何工作的 “映射”函数必须将该函数应用于给定列表中的所有元素,并生成包含应用结果的列表。所以我们给出了函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“x”和尾“xs”,我们将函数“f”应用于x,并将其附加到“xs”。但是接下来会发生什么呢?foldr的第二个参数(通常必须是某个起始值)的具体方式和内容。空名单的目的是什么? 函数“rangeTo”:我们正在创建lambda表达式,其中我们正在检查是否超出范围,如果超出范围,则结束,如果不在末尾,则给出一对,
--custom map function through foldr
map :: (a -> b) -> [a] -> [b]
map f = foldr (\x xs -> f x : xs) []
--function to create list with numbers from first argument till second and step "step"
rangeTo :: Integer -> Integer -> Integer -> [Integer]
rangeTo from to step = unfoldr (\from -> if from >= to then Nothing else Just (from, from+step)) from
所以我们给出了函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“x”和尾“xs”,我们将函数“f”应用于x,并将其附加到“xs”
事实并非如此。仔细研究实施情况:
map :: (a -> b) -> [a] -> [b]
map f = foldr (\x xs -> f x : xs) []
这里有一个隐含变量,我们可以将其添加回:
map :: (a -> b) -> [a] -> [b]
map f ls = foldr (\x xs -> f x : xs) [] ls
map
接受两个参数,一个是函数f
,一个是列表ls
。它将ls
传递到foldr
作为要折叠的列表,并将[]
作为起始累加器值传递。lambda接受一个列表元素x
和一个累加器xs
(最初是[]
),并返回一个新的累加器f x:xs
。它不会在任何地方执行头部
或尾部
x
和xs
从来不是同一个列表的一部分
让我们逐步完成评估,看看此函数是如何工作的:
map (1+) [2, 4, 8]
foldr (\x xs -> (1+) x : xs) [] [2, 4, 8] -- x = 8, xs = []
foldr (\x xs -> (1+) x : xs) [9] [2, 4] -- x = 4, xs = [9]
foldr (\x xs -> (1+) x : xs) [5, 9] [2] -- x = 2, xs = [5, 9]
foldr (\x xs -> (1+) x : xs) [3, 5, 9] [] -- xs = [3, 5, 9]
map (1+) [2, 4, 8] == [3, 5, 9]
空列表累加通过f
传递的值,从输入列表的右端开始
函数“rangeTo”:我们正在创建lambda表达式,其中我们正在检查是否超出范围,如果超出范围,则结束,如果不在末尾,则给出一对,其中第一个数字附加到结果列表中,第二个数字用作“from”的下一个值。这就是函数中发生的一切,还是我遗漏了什么 是的,事情就是这样。lambda接受一个累加器,并返回要放入列表的下一个值和一个新累加器,如果列表应该结束,则返回
Nothing
。本例中的累加器是列表中的当前值。如果该值超过范围的末尾,则列表应结束。否则,它将通过添加步长来计算下一个累加器
同样,我们可以逐步完成评估:
rangeTo 3 11 2 -- from = 3, to = 11, step = 2
Just (3, 5) -- from = 3
Just (5, 7) -- from = 3 + step = 5
Just (7, 9) -- from = 5 + step = 7
Just (9, 11) -- from = 7 + step = 9
Nothing -- from = 9 + step = 11, 11 >= to
rangeTo 3 11 2 == [3, 5, 7, 9]
了解
foldr
如何在列表上运行。最好将foldr的
foldr step z xs
= x1 `step` foldr step z xs1 -- where xs = x:xs1
= x1 `step` (x2 `step` foldr step z xs2) -- where xs = x1:x2:xs2
= x1 `step` (x2 `step` ... (xn `step` foldr step z [])...) -- where xs = x1:x2...xn:[]
及
对于您的情况:
foldr (\x xs -> f x : xs) []
在哪里
根据foldr
的定义,最里面的表达式
(xn `step` foldr step z [])
首先进行评估,即
xn `step` foldr step z []
= step xn (foldr step z [])
= step xn z
= step xn [] -- z = []
= f xn : [] -- step = (\x xs -> f x : xs)
= [f xn]
接下来会发生什么?评估正在进行中
x(n-1) `step` (xn `step` foldr step z [])
= step x(n-1) [f xn]
= f x(n-1) : [f xn]
= [f x(n-1), f xn]
直到:
x1 `step` (x2 ...
= step x1 [f x2, ..., f xn]
= [f x1, f x2, ... f xn]
foldr
表示列表中的(:)
,你写的是f
,而不是[]
,你写的是z
(初始累加器值)。我看到了foldr
的解释,但我不理解[]
。如果f
代表(4+)
和list,我们传递给map的是[1,2,3]
,那么:第一次迭代:list分解为x=1和xs=[2,3],然后我们在x上使用f,得到5,并在它的list前面加上前缀,得到结果[5,2,3]。然后,foldr从这个列表中取5,并在空列表的前面加上它。在第二次迭代x=2,xs=[3]中,我们重复前面的步骤。是否正确?f
通常不代表(4+)
,因为它接受一个元素和累加器作为输入。要直接回答您的问题,这里的空列表的目的是作为累加器的初始值foldr
完全应用时,需要3个参数:一个“折叠函数”f
(需要2个参数),一个初始值z
(这里是空列表),以及要折叠的列表。它所做的是,从列表的末尾开始,向后操作,对当前列表元素和当前累加器应用f
,生成一个新的累加器。因此,它从右到左遍历列表,同时更新累加器,并返回最终值。这更有意义吗?另一方面:这是两个完全不同的问题。您最好在单独的问题中询问unfover
。
x(n-1) `step` (xn `step` foldr step z [])
= step x(n-1) [f xn]
= f x(n-1) : [f xn]
= [f x(n-1), f xn]
x1 `step` (x2 ...
= step x1 [f x2, ..., f xn]
= [f x1, f x2, ... f xn]