这个Haskell列表代码有什么问题?

时间:2017-05-06 10:18:28

标签: function haskell functional-programming

这是我想要做的一个例子。

let b = ["this","is","a","test!"]

"xx" ++ (b!!3)

这会给我“xxtest!”

基本上,如果列表包含带有感叹号的任何字符串,则“xx”将添加到此特定字符串中。我的问题是如何将其实现为正确的功能。

目前我得到了这个

replaceElement [] = []
replaceElement (x:xs) =
      if '!' `elem` x
      then ["xx"] ++ x : replaceElement xs
      else x: replaceElement xs

但是这个函数只是将“xx”作为元素添加到列表中,它不会被添加到列表中的特定字符串中。如何使用“xx”++(b !! x),其中x是带有感叹号的字符串的位置。

3 个答案:

答案 0 :(得分:4)

表达式

["xx"] ++ x : replaceElement xs

实际上被解析为

["xx"] ++ (x : replaceElement xs)

正是您所描述的内容:将"xx"插入到结果列表中。你想要做的是:

("xx" ++ x) : replaceElement xs

答案 1 :(得分:3)

关键是如何解析["xx"] ++ x : replaceElement xs。这取决于运算符的 fixities

GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
Prelude> :info :
-- ...
infixr 5 :
Prelude> :i ++
(++) :: [a] -> [a] -> [a]   -- Defined in ‘GHC.Base’
infixr 5 ++

因此,:++都是右关联运算符,具有相同的优先级。右关联意味着a : b : c被解析为a : (b : c),而不是(a : b) : c(左关联infixl就是这种情况)。由于优先级相同,如果混合:++,i.s。

,这仍然有效。
["xx"] ++ x : replaceElement xs  ≡  ["xx"] ++ (x : replaceElement xs)

IOW,您只是将["xx"]添加到整个结果中,但各个元素永远不会与"xx"联系。为此,您需要将"xx"x分组。那么额外的括号是不必要的(事实上这些可能会让你失望:将"xs"包装在一个额外的层中意味着你不再按照预期的方式处理字符串级别,而是在字符串列表级别上)。

更好的选择当然是不做任何手动递归:你只是将相同的操作应用于列表的所有元素;这就是map的用途:

replaceElement = map $ \x -> if '!'`elem`x
                              then "xx"++x
                              else x

答案 2 :(得分:0)

您也可以将map与辅助函数一起使用,如;

addxx :: [String] -> [String]
addxx = map checkBang
        where checkBang s | last s == '!' = "xx" ++ s
                          | otherwise     = s