2017-05-06 74 views
0

這是我想要做的一個例子。這個Haskell列表代碼有什麼問題?

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是帶有感嘆號的字符串的位置。

回答

4

表達

["xx"] ++ x : replaceElement xs 

實際上被解析爲

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

你描述的正是其中的作用:插入"xx"到結果列表。你想要做的是:

("xx" ++ x) : replaceElement xs 
3

關鍵的是如何解析["xx"] ++ x : replaceElement xs

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) 

督察,你只是在前面加上["xx"]整個結果,但個別元素不會接觸"xx"得到。要達到這個目標,您需要將"xx"x分組。額外的括號是不必要的然後(事實上,這些可能會讓你失望:在額外的層中包裝"xs"意味着你不再像預期的那樣工作在字符串級別,而是在字符串級別上)。當然


一個更好的選擇將不會做任何手動遞歸:你只是將相同的操作列表中的所有元素;這就是map是有:

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

你也可以使用map與助手功能等;

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