Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 了解foldr和Unfover的工作_Haskell - Fatal编程技术网

Haskell 了解foldr和Unfover的工作

Haskell 了解foldr和Unfover的工作,haskell,Haskell,我很难理解这些代码是如何工作的 “映射”函数必须将该函数应用于给定列表中的所有元素,并生成包含应用结果的列表。所以我们给出了函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“x”和尾“xs”,我们将函数“f”应用于x,并将其附加到“xs”。但是接下来会发生什么呢?foldr的第二个参数(通常必须是某个起始值)的具体方式和内容。空名单的目的是什么? 函数“rangeTo”:我们正在创建lambda表达式,其中我们正在检查是否超出范围,如果超出范围,则结束,如果不在末尾,则给出一对,

我很难理解这些代码是如何工作的

“映射”函数必须将该函数应用于给定列表中的所有元素,并生成包含应用结果的列表。所以我们给出了函数f和一些列表,然后在lambda表达式中,我们的列表转换为头“x”和尾“xs”,我们将函数“f”应用于x,并将其附加到“xs”。但是接下来会发生什么呢?foldr的第二个参数(通常必须是某个起始值)的具体方式和内容。空名单的目的是什么? 函数“rangeTo”:我们正在创建lambda表达式,其中我们正在检查是否超出范围,如果超出范围,则结束,如果不在末尾,则给出一对,其中第一个数字附加到结果列表中,第二个数字用作“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
所以我们给出了函数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]