2017-11-11 62 views
3

我在Haskell中工作,爲測試做準備。當前任務要求按以下公式標記字符串: 運行「tokenize str separate remove」時,應該輸出一個字符串列表。出現在字符串「分開」中的「str」中的每個字符應該是一個字符的字符串。出現在「刪除」字符串中的「str」中的每個字符應該被刪除。不分開或刪除的字符應該捆綁在一起。Haskell中的遞歸標記器

實施例顯示,

tokenize "a + b* 12-def" "+-*" " " 

應該輸出

["a", "+", "b", "*", "12", "-", "def"] 

下面

tokenize :: String -> String -> String -> [String] 
tokenize [] _ _ = [] 
tokenize [x] _ _ = [[x]] 
tokenize (x:xs) a b  | x `elem` a = [x] : tokenize xs a b 
         | x `elem` b = tokenize xs a b 
         | otherwise = (x:head rest) : tail rest 
           where 
             rest = tokenize xs a b 

它工作在一定程度上,這個問題是它的運營商在例如我當前的代碼與之前的信件捆綁在一起。

這樣

["a+","b*","12-","def"] 

儘管運營商在不同的字符爲。

+2

問題出在''|否則=(x:頭部休息):尾部休息,無論「頭部休息」是什麼,你都在'頭部休息'上放置'x'。 – sjakobi

回答

1

首先,tokenize [x] _ _可能不是你想要的,因爲tokenize "a" "" "a"最後應該是["a"],應該是[]。其次,請勿撥打分隔符和清除列表String s。他們只是[Char] s。下面沒有區別,因爲type String = [Char],但同義詞的意義在於使語義含義更清晰,而且您沒有真正使用String s,因此您的功能不值得。此外,您應該將參數洗牌爲tokenize seps rems str,因爲這會使咖啡更容易。最後,您可能希望使用Data.Set而不是[Char],但我不會在此處使用它來保持接近該問題。

問題本身是| otherwise = (x:head rest) : tail rest,它將任何非特殊字符粘到下一個標記上,即使該標記應該是分隔符。在你的情況下,一個例子是當head rest = "+"x = 'a',你加入他們,所以你有"a+"。你需要進一步保護。

(另外:你的縮進搞砸:where條款綁定到整個方程,所以它的整個所有的衛兵看到它應縮進,使得很清楚。)

tokenize :: [Char] -> [Char] -> String -> [String] 
tokenize _ _ "" = [] 
tokenize seps rems (x:xs) 
    | x `elem` rems      = rest 
    | x `elem` seps      = [x]:rest 
    -- Pattern guard: if rest has a single-char token on top and that token is a sep... 
    | ([sep]:_) <- rest, sep `elem` seps = [x]:rest 
    -- Otherwise, if rest has a token on top (which isn't a sep), grow it 
    | (growing:rest') <- rest   = (x:growing):rest' 
    -- Or else make a new token (when rest = []) 
    | otherwise       = [x]:rest 
    where rest = tokenize xs seps rems 

您可能也用filter

tokenize seps rems = tokenize' . filter (not . flip elem rems) 
    where tokenize' "" = [] 
     tokenize' (x:xs) 
      | x `elem` seps      = [x]:rest 
      | ([sep]:_) <- rest, sep `elem` seps = [x]:rest 
      | (growing:rest') <- rest   = (x:growing):rest' 
      | otherwise       = [x]:rest 
      where rest = tokenize' xs