2015-05-31 40 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