2015-05-31 76 views
1

一直存在一些與此有關的實際問題,並且在任何閱讀中都無法找到任何指導。一直負責實現函數以完成Connect 4的Haskell版本。該板被表示爲使用Data.List的片段列表。在Haskell中更改列表中的單個值[家庭作業]

其中一個功能是放棄一塊給定的塊和列號。爲此,我只想將該部分添加到相應的列中,並完成它,但似乎能夠做到這一點的唯一方法是通過列表遞歸,直到我到達右側列,然後添加該部分。

有什麼辦法可以做得更好?

我可怕的代碼如下:

cheatPiece :: GameState -> Int -> Piece -> GameState 
cheatPiece [] _ _ = [] 
cheatPiece (xs:xss) 0 x = (x:xs) : xss 
cheatPiece (xs:xss) n x = xs : cheatPiece xss (n-1) x 
+0

如果你不想自己做,鏡頭是要走的路。 – AJFarmar

回答

3

我不認爲你的實現是可怕的。這幾乎是使用不可變鏈接列表的標準方法。

我認爲使它感覺笨拙的主要原因是使用索引和鏈表不會很自然。

所以,在一個家庭作業的情況下,你的實現是,我認爲,最正確的方式來實現cheatPiece。如果您可以控制董事會演示文稿,我可能會考慮使用vectorIntMap來存儲這些列。

還有總是lens它可以讓你使用更簡潔抽象嵌套的,一成不變的結構工作,但如果你還是新的Haskell那麼lens包絕對沒有學習曲線的溫柔。

import Control.Lens 

data Piece = X | O deriving Show 
type GameState = [[Piece]] 

cheatPiece :: GameState -> Int -> Piece -> GameState 
cheatPiece st i p = st & ix i %~ (p:) 
+0

你會如此善良並詳細說明'cheatPiece'的定義嗎? – mucaho

3

您可以使用takedrop功能和列表索引操作符!!

cheatPiece xss n x = take n xss ++ [x : (xss !! i)] ++ drop (n + 1) xss 

或者有splitAt它結合採取落 - 我會在檢查拋出當指數太大:

cheatPiece xss n x = case splitAt n xss of 
         (_, []) -> error "out of range" 
         (yss, zs:zss) -> yss ++ [x:zs] ++ zss 

但是我很想寫一個概括說函數的指數下修改的元素:

modifyAt :: Int -> (a -> a) -> [a] -> [a] 
modifyAt n f xs = case splitAt n xs of 
        (_, []) -> error "out of range" 
        (ys, z:zs) -> ys ++ [f z] ++ zs 

其可以像這樣使用:

> modifyAt 3 (+1000) [0..9] 
[0,1,2,1003,4,5,6,7,8,9] 

然後你的函數將

cheatPiece xss n x = modifyAt n (x:) xss 
+0

謝謝你。我已經選中的第一個作爲主要回答圍繞某種理智的方式這樣做的難度我的問題,但您的建議是優秀的,絕對睜開眼睛多一點,以解決這一方式的不同。 – Syzorr