2017-11-11 66 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