我一直在学习一些Haskell,我想出了一个解决方案,我试图找出一个练习。
changeStr :: Int -> Char -> String -> String
changeStr x char zs = (take (x-1) zs) ++ [(changeChar (head (take x zs)) char)] ++ (drop x zs)
changeChar :: Char -> Char -> Char
changeChar x y = y
我只是想问一下,有没有其他方法可以使用不同的方法以更简单的方式做到这一点?
答案 0 :(得分:2)
尖叫为概括的东西是changeChar
。它实际上非常接近一个名为Prelude
的非常常见的Haskell 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))
答案 1 :(得分:1)
除了函数changeChar
只是flip const
之外,你所拥有的几乎是你所需要的,你可以将你的内容重写为
changeStr x char zs = take (x-1) zs ++ [char] ++ drop x zs
如果您想要变得复杂,可以使用splitAt
中的Data.List
以及fmap f (a, b) = (a, f b)
changeStr idx c str = uncurry (++) $ fmap ((c:) . tail) $ splitAt (idx - 1) str
如果你想变得非常复杂,你可以问pointfree
机器人如何在没有显式函数参数的情况下编写它
changeStr = ((uncurry (++) .) .) . flip ((.) . fmap . (. tail) . (:)) . splitAt . subtract 1