2017-04-08 73 views

回答

2

使用lens pacakge

如果我們知道功能ID開始可以像一個鏡頭:

import Control.Lens 
> [1,2,3,4] ^. id 
[1,2,3,4] 

然後我們就可以移動到列表如何可以修改:

> [1,2,3,4] & id %~ (99:) 
[99,1,2,3,4] 

以上允許插入列表的開始。要關注列表的後面部分,我們可以使用Control.Lens.Cons模塊中的_tail。

> [1,2,3,4] ^. _tail 
[2,3,4] 
> [1,2,3,4] & _tail %~ (99:) 
[1,99,2,3,4] 

我們概括本作的第n個位置

> :{ 
let 
_drop 0 = id 
_drop n = _tail . _drop (n - 1) 
:} 
> [1,2,3,4] ^. _drop 1 
[2,3,4] 
> [1,2,3,4] & _drop 0 %~ (99:) 
[99,1,2,3,4] 
> [1,2,3,4] & _drop 1 %~ (99:) 
[1,99,2,3,4] 

最後一步了所有類型的一個缺點例如,我們可以使用利弊或<概括這個|。

> [1,2,3,4] & _drop 1 %~ (99<|) 
[1,99,2,3,4] 
> import Data.Text 
> :set -XOverloadedStrings 
> ("h there"::Text) & _drop 1 %~ ('i'<|) 
"hi there" 
4

你可以建立一個insertAt功能是這樣的:

對於這樣的問題
insertAt :: a -> Int -> [a] -> [a] 
insertAt newElement 0 as = newElement:as 
insertAt newElement i (a:as) = a : insertAt newElement (i - 1) as 

一種策略是,直到邊緣的情況下被發現對於一些邊緣情況和使用遞歸編寫代碼。

上述lens包簡化了處理數據結構,因爲代碼可能變得更短且更好編寫,但代價是要額外學習一個庫。

這兩個例子都強調了有幾種方法可以解決您的問題。我建議查看Data.List模塊,以獲得對典型列表操作的進一步瞭解。 drop函數的source可能是您的良好開端。 也提供splitAt功能可能是一個適合您的問題的積木。


由於Shersh提到正確上述實施insertAt是有點瑕疵:它不檢查消極立場,以及在一個給定的只是繼續遞歸的情況下。如果列表無限,這可能特別糟糕。

我們可以很容易地通過使用警衛提高執行:

insertAt :: a -> Int -> [a] -> [a] 
insertAt newElement _ [] = [newElement] 
insertAt newElement i (a:as) 
    | i <= 0 = newElement:a:as 
    | otherwise = a : insertAt newElement (i - 1) as 

此實現試圖通過有疑問時,請立即插入newElement正確的事情。 也可以寫一個版本的insertAt,與其拋出錯誤到我們的臉:

import Data.Monoid ((<>)) 
import qualified Data.List as List 

insertAt :: a -> Int -> [a] -> [a] 
insertAt newElement i as 
    | null as && i != 0 = error "Cannot insert into empty list other than position 0." 
    | null as && i == 0 = [newElement] 
    | i >= 0 = let (prefix, suffix) = List.splitAt i 
      in prefix <> [i] <> suffix 

這個版本也使得簡潔的使用List.splitAt

+0

如果通過了負整數,則您的解決方案不起作用。我認爲在這種情況下不要默默地失敗,但返回有意義的東西或禁止傳遞不正確的輸入是很好的技巧。 – Shersh

+0

是的,我同意你的意見。類型系統贏得的只有很多 - 沒有理由通過編寫不安全的代碼來交換它的優勢。 –

相關問題