2015-09-27 47 views
4

需要從Haskell列表中的右邊開始每增加第二個項目,但保持原點順序(例如reverse不是這種情況)。例如:進程Haskell列表從右到左保持原點順序

f [1, 2, 3] -- [1, 3, 3] 

f [1, 2, 3, 4] -- [2, 2, 4, 4] 

我試着像一個下面:

fc ([]) = [] 
fc (x:[]) = [x] 
fc (x:[y]) = [x+1,y] 
fc(x:xs) = fc [x] : (fc xs) -- this line is wrong 

附:很顯然,我可以扭轉(但希望瞭解原任務)列表兩次,並應用類似:

helper (x:y:tail) = [x, y+1] ++ tail 
fc x = reverse (helper (reverse x)) 
+0

你的第二個例子是改變第1和第3項。你想做什麼? – MASL

+0

@MASL的任務是從右邊增加每個2。所以看右邊的列表:右邊的第二個是'3 - >(3 + 1)= 4',現在跳過'2',在第四個'1 - >(1 + 1)= 2'之後。所以結果'[2,2,4,4]' – Dewfy

+0

好的。監視那個細節。 – MASL

回答

2

這可以有效地使用左摺疊來完成:

inc :: Num a => [a] -> [a] 
inc xs = foldl go (\_ _ acc -> acc) xs id (+ 1) [] 
    where go run x f g acc = run g f (f x: acc) 

注意,甚至認爲這是左折,列表使用利弊(:)運營商建;它將以線性方式執行而不是二次方式(類似於difference lists中的構造)。

\> inc [1, 2, 3] 
[1,3,3] 
\> inc [1, 2, 3, 4] 
[2,2,4,4] 

它也可以被推廣到比id(+ 1)其他交替功能。

4

從右到左將扭轉它處理的Haskell列表的典型方式。既然你想有原來的順序爲結果,你只需再次逆轉:

f1 = reverse . zipWith (+) (cycle [0,1]) . reverse 

但如果你真的願意,你可以在每個遞歸調用返回兩個更新的尾巴和指示是否標誌從年底開始計數時位置,甚至讓你知道是否增加元素在該位置或不:

f2 = snd . g 
    where 
    g []  = (False, []) 
    g (x:xs) = let (addOne, xs') = g xs 
       x' = if addOne then x + 1 else x 
      in (not addOne, x':xs') 

我們基本上在映射列表中的功能,但這個功能需要獲取計算一個額外的參數從列表的右端開始。還有我們可以使用一個標準功能:

import Data.List (mapAccumR) 
f2' = snd . mapAccumR g False 
    where 
    g addOne x = (not addOne, if addOne then x + 1 else x) 
+0

我真的很喜歡你的第二個答案。請注意,這兩種方法可能會有很大不同。雙反向通常會分配更多的內存,但只有基準可以說哪個更好。 – dfeuer

4

我想你想要的東西更清潔的規格是你,如果長度爲偶數和奇數indicies如果長度是奇數遞增甚至indicies。例如,當從零開始索引時,長度爲3的列表導致索引1遞增。要做到這一點的方法之一是明顯的兩個直通解決方案:

f xs = zipWith (+) (cycle sol) xs 
where sol = map fromEnum [even len, odd len] 
     len = length xs 

這可以一次完成(不依賴於編譯器融合規則)的「綁結」。例如(使用手動遞歸風格作爲通信手段)。

f2 xs = let (isEven, result) = go isEven xs in result 
where 
    go _ []  = (True,  []) 
    go e (x:xs) = let (ne,rest) = go (not e) xs 
       in (not ne, x+fromEnum e : rest) 
+0

不錯的嘗試!確實它給出了正確的結果。我的起源問題受到試圖在Prolog和Haskell中找到共同部分的啓發。 Prolog爲您提供了2種「迭代」和「遞歸」的方式來處理任何方向的列表。所以看着Haskell,我只能看到'f(x:xs)' - 遞歸方式 – Dewfy

+0

我不明白raymonad的答案如何連結一個結。 – dfeuer

+0

@dfeuer哎呀,我瞥了一眼太快。我的錯。 –

0

我喜歡托馬斯的解決方案。不過,我認爲在這裏只需一個簡單的foldr即可。

process = snd . foldr (\x (b,xs) -> (not b, x + fromEnum b:xs)) (False,[]) 
+0

這與raymonad的第二個答案是一樣的,除了你已經內聯'mapAccumR'。 – dfeuer

+0

在計算答案時,它不必在概念上有所不同。另外,我發現'foldr'對於初學者來說比'mapAccumR'更容易理解,因爲它在功能語言中使用得更加廣泛。 – is7s

+0

我會承認這一點,但整個情況有點不同尋常。 'mapAccumL'更爲常見,很少有初學者會理解它翻譯成'foldr'。 – dfeuer