回答
首先,类型的foldr
:(a -> b -> b) -> b -> [a] -> b
考虑使用成上下文,foldr
发生在3个参数:一个功能(即在一个接受一个列表和B的元件一个累加器。并返回累加器),累加器的起始值和一个列表。 foldr
通过列表应用功能后返回累加器的最终结果。
至于这段代码:
length = foldr (\_ n -> 1 + n) 0
正如你所看到的,它缺少列表 - 所以右侧的返回值是将在一个列表,并产生一个功能Int(与0
相同)。类型:[a] -> Int
。
至于什么右手侧是指:(\_ n -> 1 + n) 0
\
装置声明的未命名函数
_
装置忽略从列表中元素(对应于在a
的foldr
类型)。如您所知,foldr
将通过列表并将该函数应用于每个元素。这是传递给函数的元素。我们在length
函数中没有任何用处,所以我们表示它应该被忽略。
n
是Int作为累加器传入的参数。
->
手段返回
1 + n
将增加累加器。您可以想象,返回值将传递回foldr
,并且foldr
会将该值保存到下一个函数(\_ n -> 1 + n)
的调用中。
括号外的0
是计数器的起始值。
只是一个音符:Haskell不是我的语言 - 我了解了它并理解它是如何工作的,但我没有用Haskell编写太多代码。如果有任何错误 - 请指出。 – nhahtdh 2012-07-11 04:18:28
谢谢你的解释。 – hattenn 2012-07-11 04:22:28
@nhahtdh - 很好的解释,但是右边的类型是'[a] - > Integer';由于'foldr'应用于两个参数,所以您可以从其类型中删除前两个参数,并且最终的类型是剩下的(在统一后)。除了因为数字文字是多态的,结果类型实际上并不是'整型'但是是多态的,所以'Num b => [a] - > b'。 – 2012-07-11 08:42:26
功能foldr
是折叠与右结合运营商的列表,你可以很容易理解,如果你使用操作(+)
功能做什么,(该函数具有相同的行为sum
):
foldr (+) 0 [1,2,3,4,5] = 1+(2+(3+(4+(5+0))))
为了您的长度的功能,它相当于:
foldr (\_ n -> 1 + n) 0 [1,2,3,4,5] = 1+(1+(1+(1+(1+0))))
这正是foldr
为
有几种等同的方法来理解它。第一招:foldr f z [1, 2, 3, 4, ..., n]
计算以下值:
f 1 (f 2 (f 3 (f 4 (f ... (f n z)))))
所以你的情况:
length [1,2,3,4] = foldr (\_ n -> 1 + n) 0 [1,2,3,4]
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 ((\_ n -> 1 + n) 4 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 ((\_ n -> 1 + n) 3 (1 + 0)))
= (\_ n -> 1 + n) 1 ((\_ n -> 1 + n) 2 (1 + (1 + 0)))
= (\_ n -> 1 + n) 1 (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + (1 + 0)))
= 1 + (1 + (1 + 1))
= 1 + (1 + 2)
= 1 + 3
= 4
另外一个就是从这个功能,启动该份名单:
listCopy :: [a] -> [a]
listCopy [] = []
listCopy (x:xs) = x : listCopy xs
那可能看起来像一个微不足道的功能,但foldr
基本上就是这样,但除了硬编码空列表[]
和配对构造函数:
进入右侧,我们改为使用一些任意常量和作为参数提供的函数。我有时喜欢把这些论点fakeCons
和fakeNil
(cons
和nil
是:
运营商和Lisp编程语言[]
不变的名称),因为从某种意义上说你是“复制”列表中,但使用假构造函数:
foldr fakeCons fakeNil [] = fakeNil
foldr fakeCons fakeNil (x:xs) = fakeCons x (subfold xs)
where subfold = foldr fakeCons fakeNil
所以这种解释下,您length
功能是“复制”的列表,但不是它的使用0
空列表,而不是:
它丢弃的元素,加入1到正在运行的总。
而这里又的foldr f z xs
第三旅游解说:
z
是你的问题的解决方案时列表为空。f
是一个函数,有两个参数:列表中的一个元素,和部分解决:解决您的问题,为那些看起来则传递到f
元素的右边的元素列表。然后产生一个“更大的一个元素”的解决方案。
所以在length
情况:
- 空列表的长度是0,所以这就是为什么你使用0作为第二个参数
foldr
。 - 如果
xs
的长度为n
,则x:xs
的长度为n+1
。这就是你对foldr
,\_ n -> n + 1
所做的第一个参数:它正在计算一个列表的长度,作为参数给出列表的第一个元素(在这种情况下我们忽略)和列表的其余部分的长度(n
) 。
这种关于foldr
的思考方式非常强大,不应低估。基本上,在您作为foldr
的第一个参数传递的函数中,允许您假设您尝试解决的问题已经为所有比您处理的列表短的列表解决。你所有的参数函数必须做的是计算一个长度为一个元素的列表的答案。
- 1. 确定Nvarchar长度
- 2. 数组长度不确定
- 3. 确定录音的长度?
- 4. 确定长度方差
- 5. 确定MIDI音符长度
- 6. FIX - 确定消息长度?
- 7. MySQL确定最长的VarChar长度
- 8. C++使用ODBC绑定参数预先确定VARCHAR的长度
- 9. 移调的长度和过滤器只是一个foldr相似
- 10. 在JS中正确使用长度
- 11. 在ng-model上使用$ scope时,输入长度不确定
- 12. 如何确定使用MySQL组查询的长度查询
- 13. 使用Assimp导入时确定骨骼长度
- 14. 使用DirectShow确定音频文件的长度
- 15. 使用PowerShell确定文本文件中一行的长度
- 16. 为什么'Data.List.null'使用'foldr'?
- 17. Haskell - 使用foldr的MinMax
- 18. 使用foldr实现邮编
- 19. 使用foldr实现inits
- 20. 无法确定DKIM密钥长度
- 21. 确定DB2文本字符串长度
- 22. 确定代码段的长度
- 23. 确定输入的getElementById长度
- 24. 正确的方法来定义长度
- 25. 如何确定Ruby中Fixnum的长度?
- 26. 确定ACPI状态文件的长度
- 27. 确定MIPS32中字符串的长度
- 28. 如何确定YouTube视频的长度?
- 29. 确定阵列分配的长度
- 30. 确定Intent.STREAM_EXTRA(Android)的内容长度
请参阅http://stackoverflow.com/questions/7704960/how-to-write-a-length-function-using-foldr-in-haskell开始。 – 2012-07-11 04:04:27
另请参阅:http:// learnyouahaskell。com/higher-order-functions#folds – 2012-07-11 09:27:23
如果您使用'foldl''会更好,这对您的堆栈很有用 'length = foldl'(\ n _ - > n + 1)0' – Ronson 2013-10-08 06:45:29