0

晚上,

这是我在 Haskell 中尝试等效于“str_replace”

strReplace :: (Char, Char) -> String -> String -> String {- Original (y) Parsed (z) -}
strReplace _ "" y = y
strReplace x y z = if (y !! 0) == fst x then strReplace x (drop 1 y) (z:([snd x])) else        strReplace x (drop 1 y) (z:(y!!0))

本质上,第一个 Tuple 是要替换的字符(即 ('A', 'B') 替换所有 As to Bs,第二个参数是要解析的 String,第三个参数应该始终为空字符串。编译器返回

*** Expression     : z : [snd x]
*** Term           : z
*** Type           : [Char]
*** Does not match : Char

想法?:)

4

2 回答 2

1

您的代码的问题z : [snd x]是不正确,z是一个列表,但:希望它是一个元素。这可以通过使用来修复z ++ [snd x]

如果查看类型签名有帮助

(:) :: a -> [a] -> [a]
(++) :: [a] -> [a] -> [a]

或者在您的特定情况下

(:) :: Char -> String -> String
(++) :: String -> String -> String

但是,如果我可以建议对您的代码进行一些改进,首先strReplace不应该强迫您传递一个空字符串

strReplace :: (Char, Char) -> String -> String

接下来,我们可以通过两种方式做到这一点,使用高阶函数或显式递归。

-- recursion
strReplace _ "" = "" -- Base case
strReplace (a, b) (c:cs) | a == c = b : strReplace (a,b) cs
                         | otherwise = c : strReplace (a, b) cs

所以这里如果字符串为空,我们就完成了,否则我们进行模式匹配,如果第一个字符是要替换的,我们替换它并递归,否则我们不替换它并递归。

map虽然这实际上可以更干净地完成

strReplace (a, b) s = map (\c -> if c == a then b else c) s

这与我们之前的版本相同,但map抽象了循环逻辑。

于 2013-10-23T15:54:47.917 回答
1

z 是 类型[Char]。您不能使用:to cons a [Char]into a [Char]- 查看:. 您将不得不使用++将一个附加[Char]到另一个。

附加点:

  1. strReplace有一个签名会更好的风格:: Char -> Char -> String -> String -> String
  2. 签名的风格会更好:: a -> a -> [a] -> [a] -> [a]
  3. 您不应该要求调用代码传入一个空字符串。如果他们不这样做怎么办——他们怎么知道他们犯了错误?如果您的递归调用需要它,请使用内部函数(使用letor where)。
  4. 你看到一个看起来像foo x y = if (y == ... ) ... else ...它的函数几乎总是可以通过模式匹配或守卫来改进。

要扩展第 4 点,您可以将第三行重写为

strReplace x y z | y !! 0 == fst x = ...
                 | otherwise = ...

更好的是,如果您接受我在第 1 点中的建议并将元组拆分为两个简单的Char参数,您可以这样做:

strReplace x1 x2 y@(y1:ys) z | x1 == y = ...
                             | otherwise = ...
于 2013-10-23T15:56:31.583 回答