需要概括的东西是changeChar
。它实际上非常接近于一个非常常见的 HaskellPrelude
函数,称为const
. 为了得到changeChar
我们只需要flip const
.
const :: a -> b -> a
const a b = a
changeChar :: Char -> Char -> Char
changeChar = flip const
-- = flip (\a _ -> a)
-- = \_ a -> a
-- _ a = a
除此之外,您的代码相当合理,但可以通过使用函数来清理splitAt
splitAt :: Int -> [a] -> ([a], [a])
splitAt n xs = (take n xs, drop n xs)
changeChar x char xs =
let (before, _it:after) = splitAt (x - 1)
in before ++ (char:after)
这也突出了这个定义的一个小问题,如果你的索引太大,它会引发模式匹配失败。如果我们“落到最后”,我们可以通过让函数返回一个未修改的字符串来解决这个问题
changeChar x char xs =
let (before, after) = splitAt (x - 1)
in case after of
[] -> []
(_:rest) -> char:rest
这里还有一个通用模式,即在列表中的特定位置应用修改函数。这是我们如何提取它的方法。
changeAt :: Int -> (a -> a) -> [a] -> [a]
changeAt n f xs =
let (before, after) = splitAt (n-1)
in case after of
[] -> []
(x:rest) -> (f x):rest
我们可以用它来迭代这个概念
-- | Replaces an element in a list of lists treated as a matrix.
changeMatrix :: (Int, Int) -> a -> [[a]] -> [[a]]
changeMatrix (i, j) x = changeAt i (changeAt j (const x))