首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当累加器满足一定条件时,如何从haskell的折叠函数中爆发?

当累加器满足一定条件时,如何从haskell的折叠函数中爆发?
EN

Stack Overflow用户
提问于 2018-08-07 12:40:02
回答 9查看 5.7K关注 0票数 19

在将someFunction应用于列表的每个元素之后,我正在计算列表的和,如下所示:

代码语言:javascript
复制
sum (map someFunction myList)

someFunction资源非常多,所以为了优化它,我想停止计算超过某个阈值的和。

似乎我需要使用折叠,但如果累加器达到阈值,我不知道如何突破它。我的猜测是以某种方式组成foldtakeWhile,但我不太确定是如何组成的。

EN

回答 9

Stack Overflow用户

回答已采纳

发布于 2018-08-07 13:08:10

其中一个选项是使用扫描函数,它返回foldl的中间计算列表。

因此,scanl1 (+) (map someFunction myList)将返回计算的中间和。而且,由于Haskell是一种懒惰的语言,在需要它之前,它不会计算myList的所有值。例如:

代码语言:javascript
复制
take 5 $ scanl1 (+) (map someFunction myList)

将计算someFunction 5次并返回这5项结果的列表。

在此之后,您可以使用takeWhiledropWhile,并在特定条件为True时停止计算。例如:

代码语言:javascript
复制
head $ dropWhile (< 1000) $ scanl1 (+) [1..1000000000]

当数字之和达到1000并返回1035时,将停止计算。

票数 18
EN

Stack Overflow用户

发布于 2018-08-07 13:44:27

另一种技术是使用foldMEither来捕获早期终止效果。Left显示早期终止。

代码语言:javascript
复制
import Control.Monad(foldM)

sumSome :: (Num n,Ord n) => n -> [n] -> Either n n
sumSome thresh = foldM f 0
  where
    f a n 
      | a >= thresh = Left a
      | otherwise   = Right (a+n)

若要忽略退出状态,只需使用either id id编写。

代码语言:javascript
复制
sumSome' :: (Num n,Ord n) => n -> [n] -> n
sumSome' n = either id id . sumSome n
票数 19
EN

Stack Overflow用户

发布于 2018-08-07 13:19:54

使用有界加法运算符代替(+)foldl

代码语言:javascript
复制
foldl (\b a -> b + if b > someThreshold then 0 else a) 0 (map someFunction myList)

因为Haskell不是严格的,所以只有对someFunction的调用才是计算if-then-else所必需的。fold仍然遍历整个列表。

代码语言:javascript
复制
> foldl (\b a -> b + if b > 10 then 0 else a) 0 (map (trace "foo") [1..20])
foo
foo
foo
foo
foo
15

sum [1..5] > 10,您可以看到trace "foo"只执行5次,而不是20次。

但是,您应该使用来自foldl的严格版本foldl',而不是Data.Foldable.

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51727040

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档