首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用foldr实现take

使用foldr实现take
EN

Stack Overflow用户
提问于 2013-04-08 21:10:11
回答 2查看 3.1K关注 0票数 7

这是我使用foldrtake版本

代码语言:javascript
复制
myTake n list = foldr step [] list
                where step x y | (length y) < n = x : y
                               | otherwise = y

main = do print $ myTake 2 [1,2,3,4]

输出结果不是我所期望的:

代码语言:javascript
复制
[3,4]

然后,我尝试通过在自身中插入y的长度来进行调试,结果是:

代码语言:javascript
复制
[3,2,1,0]

我不明白为什么长度是按递减顺序插入的。也许我漏掉了什么明显的东西?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-04-08 21:59:09

如果您希望使用foldr实现take,则需要模拟从左到右遍历列表。重点是让折叠函数依赖于一个额外的参数,该参数编码了您想要的逻辑,而不仅仅依赖于列表的折叠尾部。

代码语言:javascript
复制
take :: Int -> [a] -> [a]
take n xs = foldr step (const []) xs n
  where
    step x g 0 = []
    step x g n = x:g (n-1)

这里,foldr返回一个函数,该函数接受一个数值参数,并从左到右遍历列表,从中获取所需的数量。由于懒惰,这也适用于无限列表。一旦额外的参数达到零,foldr就会短路并返回一个空列表。

票数 12
EN

Stack Overflow用户

发布于 2013-04-09 01:18:58

到目前为止,其他的答案使问题变得过于复杂,因为他们似乎过于执着于foldr“从右到左”工作的概念。从某种意义上说,它是这样做的,但Haskell是一种懒惰的语言,所以使用懒惰折叠步骤的“从右到左”的计算实际上将从左到右执行,因为结果被消费了。

学习下面的代码:

代码语言:javascript
复制
take :: Int -> [a] -> [a]
take n xs = foldr step [] (tagFrom 1 xs)
    where step (a, i) rest
               | i > n     = []
               | otherwise = a:rest

tagFrom :: Enum i => i -> [a] -> [(a, i)]
tagFrom i xs = zip xs [i..]
票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15879940

复制
相关文章

相似问题

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