17

我是一名 C# 人,试图通过 Erik Meijer 的 Channel 9 网络广播自学 Haskell。我遇到了一个有趣的难题,它涉及使用 zip 和 mod 跳过列表中的每个“n”个元素。

every :: Int -> [a] -> [a]
every _ [] = []
every n xs = [x | (x,i) <- zip xs [1..], i `mod` n == 0]

我一直在想,如果我们可以避免使用 mod,它可能会更有效(对于非常大的列表或流)。

我想过懒惰地创建一个重复的整数列表,这样我们就可以简单地将 i 的值与 n 进行比较。

repeatInts :: Int -> [Int]

这样调用就会无限repeatInts 3返回。[1,2,3,1,2,3,1,2,3,1,2,3,..]

鉴于此,我们可以every像这样重新定义:

every :: Int -> [a] -> [a]
every _ [] = []
every n xs = [x | (x,i) <- zip xs (repeatInts n), i == n]

所以我的问题是:你将如何实施repeatInts

4

2 回答 2

27

使用cycle

cycle :: [a] -> [a]  

cycle将一个有限列表联系成一个循环列表,或者等效地,将原始列表的无限重复联系起来。它是无限列表上的身份。

您可以定义repeatIntscycle

*Main> let repeatInts n = cycle [1..n]
*Main> :t repeatInts
repeatInts :: (Num t, Enum t) => t -> [t]
*Main> take 10 $ repeatInts 3
[1,2,3,1,2,3,1,2,3,1]

出于好奇,GHCcycle使用

cycle [] = errorEmptyList "cycle"
cycle xs = xs' where xs' = xs ++ xs'

用纯粹的功能术语来说,这种奇怪的技术被称为打结,它创建循环数据结构而不是无限数据结构。

详情见

于 2010-01-10T00:11:13.893 回答
4

迟到的答案,但也可以这样写:

repeatInts :: Int -> [Int]
repeatInts 0 = []
repeatInts a = [1..a] ++ repeatInts a
于 2014-05-10T12:38:38.167 回答