- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我决定认真对待 Haskell,并且全神贯注于 foldl 和 foldr 的使用。他们真的很像 Clojure 的 reduce - 但我可能错了,很快就遇到了问题,我希望有人能轻松解释。
使用此文档: https://wiki.haskell.org/Foldr_Foldl_Foldl '
在深入实现我自己的 foldr/foldl 版本之前,我决定首先测试 Prelude 中的现有版本:
± |master U:2 ✗| → ghci
GHCi, version 8.6.3: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /Users/akarpov/.ghc/ghci.conf
Prelude> foldr (+) 0 [1..9999999]
49999995000000
Prelude> foldr (+) 0 [1..99999999]
*** Exception: stack overflow
没有看到(使用 foldl 时结果相同);我更期待 Clojure 的一些东西:
> (time (reduce +' (range 1 99999999)))
"Elapsed time: 3435.638258 msecs"
4999999850000001
唯一明显(且不相关)的区别是使用 +' 而不是 +,但这只是为了适应 JVM 的类型系统——生成的数字不适合 [默认] Long,并且 +' 将自动使用需要时使用 BigInteger。最重要的是,没有堆栈溢出。因此,这似乎表明 Haskell/Clojure 中的折叠/归约要么实现方式非常不同,要么我对 haskell 实现的使用是错误的。
如果相关,这些是全局项目设置:- 包:[]- 解析器:lts-13.8
最佳答案
作为the Wiki解释说,函数 (+)
的两个参数都是严格的,这意味着当您尝试执行 1 + (2 + 3)
时,您首先需要计算 (2 + 3)
。虽然乍一看这似乎不是一个大问题,但当你有一个长列表时它就会成为问题。引用维基,
to evaluate:
1 + (2 + (3 + (4 + (...))))
, 1 is pushed on the stack.Then:
2 + (3 + (4 + (...)))
is evaluated. So 2 is pushed on the stack.Then:
3 + (4 + (...))
is evaluated. So 3 is pushed on the stack.Then:
4 + (...)
is evaluated. So 4 is pushed on the stack.Then: your limited stack will eventually run full when you evaluate a large enough chain of (+)s. This then triggers the stack overflow exception.
我不太了解 Clojure,但如果 (+')
有效,那么它绝对不需要在缩减之前对两个参数进行评估,这也是 Haskell 中的解决方案.
Foldl 不会解决这个问题,因为众所周知 foldl 在返回结果之前必须遍历整个列表两次——这效率不高——即使这样 (+)
也是仍然严格,所以可归约表达式不会被归约。
要解决这个问题,您必须使用非严格函数。在标准 Prelude 中,seq::a -> b -> b
可以完全用于此目的,这就是 foldl'
的工作方式。
再次引用wiki,
foldr is not only the right fold, it is also most commonly the right fold to use, in particular when transforming lists (or other foldables) into lists with related elements in the same order. Notably, foldr will be effective for transforming even infinite lists into other infinite lists. For such purposes, it should be your first and most natural choice. For example, note that foldr (:) []==id.
foldl' 的问题在于它颠倒了列表。如果你有一个不是问题的交换函数,那么如果你的列表是有限的(记住 foldl 必须遍历它),foldl'
通常更好。另一方面,如果您的功能出于某些原因不一定需要整个列表,或者列表可能是无限的,请选择 foldr
关于Haskell 的 foldr/l 和 Clojure 的 reduce,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54858191/
foldr 和 foldMap 据我了解,可以用来定义彼此。但这怎么可能,因为后者使用幺半群,而前者却没有?我们有任何保证 foldr 的东西吗?可以有一个幺半群吗? 最佳答案 foldr :: (a
import Prelude hiding (foldr) import Control.Applicative import Data.Foldable import Data.Traversabl
首先,我了解(几乎)折叠函数。鉴于该功能,我可以很容易地计算出会发生什么以及如何使用它。 问题是关于它的实现方式,这导致函数定义略有不同,需要一些时间才能理解。更糟糕的是,大多数折叠示例具有相同类型的
我正在学习 Haskell。我有一个看起来像这样的列表: data TwoValueList a = Empty | Node a a (TwoValueList a) 我想做这个Foldable ,
给定以下示例 foldr(\ x y -> ........ 如果输入是一个列表,例如 [1,2,3] 什么是x,什么是y? 最佳答案 让我们看一下foldr 的类型。 foldr :: (a ->
嗨,我是 Haskell 的新手,我有点迷茫。我被要求这样做,但无法解决。 仅使用 foldr , bool 运算(||)和 False , 定义一个函数 or_list :: [Bool] -> B
通过单侧折叠,我的意思是关联运算符的假设原始折叠操作,不保证任何顺序。也就是说,(fold + 0 [a b c d]) 可以是 (+ (+ a b) (+ c d)) 或 (+ (+ (+ a b)
我正在尝试在无限列表上使用埃拉托色尼筛算法生成素数。我听说 foldr 会懒惰地检查列表,但每次我尝试使用以下算法时都会出现堆栈溢出异常: getPrimes :: [Int] getPrimes =
我正在尝试在无限列表上使用埃拉托色尼筛算法生成素数。我听说 foldr 会懒惰地检查列表,但每次我尝试使用以下算法时都会出现堆栈溢出异常: getPrimes :: [Int] getPrimes =
我知道 foldr 如何在 Leaf 上工作,但我不知道 foldr 如何在 Node 上工作。如果我们已经有 f 和 z 作为参数,那么参数\x z' 是什么?假设我们有 tree = Node [
这是一个简单的函数,它接受一个列表和一个数字,并计算列表的长度是否大于该数字。 例如 compareLengthTo [1,2,3] 3 == EQ compareLengthTo [1,2] 3 =
我正在做 self 练习,想知道是否有一种方法可以仅使用 foldr 找到列表中符合特定条件的左起第一项?我希望在找到第一个项目时停止递归(我知道我可能可以结合使用 take)但我很想知道是否可以只使
我正在尝试手动导出 ((.) foldr) 的类型 (.) ::(b1 -> c1) -> (a1 -> b1) -> a1 -> c1 foldr :: (a2 -> b2 -> b2) -> b2
好吧,这是使用 foldr 的过滤器函数的定义: myFilter p xs = foldr step [] xs where step x ys | p x = x : ys
我写函数foldTree从列表中构建平衡二叉树。 我必须使用 foldr没关系,我用过,但我做了insertInTree函数递归=(现在我只知道这种方式可以穿过树木=))。 更新 : 我不确定功能 i
我试图理解我正在类的讲义中的一部分。它将长度函数定义为: length = foldr (\_ n -> 1 + n) 0 有人可以解释一下这是如何工作的吗?我无法绕开它。 最佳答案 一、类型fold
我有一些 groupBy 的替代实现,这对我来说比 Data.List 中的版本更有用,因为它不需要测试是等价关系: groupBy' :: (a -> a -> Bool) -> [a] -> [[
我是 Haskell 的初学者,即使在阅读了几个对 foldr/foldl 的解释之后,我也无法理解为什么我会在下面得到不同的结果。解释是什么? Prelude> foldl (\_ -> (+1))
如果我有这个插入功能: insert x [] = [x] insert x (h:t) | x b -> b) -> b -> [a] -> b foldr1 :: (a -> a -
在解释foldr对于 Haskell 新手来说,规范的定义是 foldr :: (a -> b -> b) -> b -> [a] -> b foldr _ z [] =
我是一名优秀的程序员,十分优秀!