在Haskell中替换字符串

时间:2013-10-23 15:48:30

标签: haskell

晚上,

这是我在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))

基本上,第一个元组是被替换的字符(即('A','B')替换所有As到Bs,第二个参数是要解析的字符串,第三个参数应该总是留空string。编译器返回

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

想法? :)

2 个答案:

答案 0 :(得分: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抽象出循环逻辑。

答案 1 :(得分:1)

z的类型为[Char]。您无法使用:[Char]纳入[Char] - 请查看:的类型签名。您必须使用++将一个[Char]附加到另一个。{/ p>

补充要点:

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

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

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

    strReplace x1 x2 y@(y1:ys) z | x1 == y = ...
                                 | otherwise = ...