2017-08-07 74 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 
相關問題