我很难理解这些代码的工作方式。
“地图”功能必须将该功能应用于给定列表中的所有元素,并生成包含应用结果的列表。因此,我们给函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“ x”和尾“ xs”,我们将函数“ f”应用于x并将其附加到“ xs”。但是接下来会发生什么呢? foldr的第二个参数(通常必须是某个起始值)如何以及如何使用。出于什么目的,空列表? 和“ rangeTo”函数:我们正在创建lambda表达式,在其中我们检查是否超出范围的末端,如果超过则结束,否则给出Nothing,或者如果我们不结束,则给出第一个数字对追加到结果列表中,第二个数字用作“ from”的下一个值。这是该功能中发生的所有事情,还是我缺少了什么?
--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
答案 0 :(得分:1)
要了解 foldr
如何在列表上运行。最好将foldr
的{{3}}记为
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 step z [] = z
针对您的情况:
foldr (\x xs -> f x : xs) []
其中
step = (\x xs -> f x : xs)
z = []
根据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]
答案 1 :(得分:0)
因此,我们给函数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
。它不会在任何地方执行head
或tail
; 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表达式,在其中我们检查是否超出范围的末端,如果超出则结束,则给出Nothing,或者如果我们未结束,则给出对其中第一个数字附加到结果列表,第二个数字用作“ 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]