2017-08-07 67 views
0

我是一个Haskell编程的新手,并且我倾向于创建一个函数,它可以在n次重复列表中的每个元素,问题是当我到达列表中的最后一个元素时,我想返回到第一个元素一个在元素和做一遍,就像Haskell当我到达列表中的最后一个元素时,如何重复列表中的元素?

repeat :: Int -> [t] ->[t] 
repeat 0 [] = [] 
repeat n (x:xs) 
     | n > 0 = x : repeat (n-1) xs 
     | n < 0 =[] 

这只能打印列表时,n是完全一样的列表的大小,并会有错误如果n>长度列表 可能的结果应该是这样的:

repeat 6 [1,2,3] 

期望的结果是:1,2,3,1,2,3

如果我想获得列表中的第一个元素并再次打印,应该编辑什么? 谢谢!

+6

'let repeat n = take n。周期' –

回答

4

正如马克·塞曼评论是采取n元素从列表中的循环一样简单,所以

repeat :: Int -> [t] -> [t] 
repeat n = take n . cycle 

如果你想完全展开的代码会或多或少是这样的:

repeat :: Int -> [t] ->[t] 
repeat 0 [] = [] 
repeat n (x:xs) | n > 0  = x : repeat (n-1) (xs ++ [x]) 
       | otherwise = [] 

这个想法是,你消耗你的每个物品附加到列表进行处理。 这里有一个live example

+0

这很酷,谢谢你的解释。这真的很有帮助! –

+0

将'xs ++ [x]'作为递归的第二个参数调用'repeate'的性能有什么后果?我认为添加到列表的末尾会使函数在列表中元素的数量上运行时间二次方。 (由于Haskell是懒惰的,我认为这将表现出来的方式是从列表中获得一个元素N个thunks将不得不被评估(其中N是元素的数量)))。 [Chi的回答](https://stackoverflow.com/a/45542340/452775)中的解决方案不存在此问题。 – Lii

+2

@Lii,这是完全正确的,我只是保持简单来解释主要思想,他们的方式是使用'repeat n = take n。循环“方法。 – Netwave

1

一个基本的选择是保持两个列表:其中一个是通过模式匹配“消耗”,而另一个记住完整列表,以便我们可以在需要时重新开始。

-- requires n >= 0 and nonempty full 
repeatAux :: Int -> [t] -> [t] ->[t] 
repeatAux 0 _  _full = [] 
repeatAux n []  full = repeatAux n full full 
repeatAux n (x:xs) full = x : repeatAux (n-1) xs full 

repeat :: Int -> [t] ->[t] 
repeat n _ | n <= 0 = [] 
repeat _ [] = error "repeat: empty list with n>0" 
repeat n full = repeatAux n full full 

这可以通过使用本地功能,使我们能够避免绕过full名单得到改善。

repeat :: Int -> [t] ->[t] 
repeat n _ | n <= 0 = [] 
repeat _ [] = error "repeat: empty list with n>0" 
repeat n full = go n full 
    where 
    go 0 _  = [] 
    go n []  = go n full 
    go n (x:xs) = x : go (n-1) xs 
相关问题