2

我一直在学习一些 Haskell,我想出了一个解决方案来解决我试图弄清楚的一个练习。

  • 将一个 Char 更改为 String 中指定位置的另一个指定 Char
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

我只是想问有没有其他方法可以使用不同的方法以更简单的方式做到这一点?

4

2 回答 2

2

需要概括的东西是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))
于 2013-11-12T22:51:00.370 回答
1

What you have is pretty much what you need, except the function changeChar is just flip const, and you could rewrite yours as

changeStr x char zs = take (x-1) zs ++ [char] ++ drop x zs

If you wanted to be complicated, you could use splitAt from Data.List and the fact that fmap f (a, b) = (a, f b)

changeStr idx c str = uncurry (++) $ fmap ((c:) . tail) $ splitAt (idx - 1) str

And if you wanted to be really complicated, you could ask the pointfree bot how to write it without explicit function arguments

changeStr = ((uncurry (++) .) .) . flip ((.) . fmap . (. tail) . (:)) . splitAt . subtract 1
于 2013-11-12T22:52:12.500 回答