对此有一些实际问题,并且无法在任何阅读中找到任何指导。已经负责实现函数来完成连接4的Haskell版本。该板使用Data.List表示为片段列表。
其中一个功能是根据片段和列号删除一个片段。为此,我想将这个片段添加到相应的列并完成它,但我似乎能够做到的唯一方法是通过列表递归,直到我到达正确的列然后添加片段。 / p>
有没有办法更好地做到这一点?
我的可怕代码如下:
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 :(得分:3)
我认为你的实施完全不可靠。这几乎是使用不可变链接列表的标准方法。
我认为使其感到笨拙的主要原因是使用索引和链接列表永远不会很自然。
因此,在家庭作业的背景下,我认为,您的实施是实施cheatPiece
的最正确方法。如果您可以控制电路板演示文稿,我可以考虑使用Source或vector
来存储列。
还有IntMap
,它允许你使用terser抽象来处理嵌套的,不可变的结构,但是如果你还是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:)
答案 1 :(得分:3)
您可以使用take
和drop
函数以及列表索引运算符!!
。
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