2013-11-28 34 views
0

給出一個字符串「3 + a * 6」我該如何確定一個一個的詞位?我知道我的代碼缺少classify xs部分,但我不知道該把它放在哪裏。誰能幫我這個? (語言是在Haskell)分類輸入字符串的詞位

classify :: String -> String 
classify (x:xs) 
     |x == '+' = "PLUS" 
     |x == '-' = "MINUS" 
     |x == '*' = "MULT" 
     |x == '/' = "DIV" 
     |x == '(' = "LP" 
     |x == ')' = "RP" 
     |isAlpha x = "VAR" 
     |isDigit x = "CONST" 
     |otherwise = error "Cannot determine lexeme" 

回答

0

如果你真的只需要一個標記器,下面是如何在沒有parsec的情況下做到這一點。我爲標記類型定義了一個額外的ADT(當然,您可以將其轉換回字符串),並且必須更改返回類型,因爲您會得到一系列標記。

type Error = String 
data Token = Plus | Minus | Mult | Div | Lp | Rp 
      | Var | Const | Whitespace deriving (Show, Eq) 

tokenTable = [('+', Plus), ('-', Minus), ('*', Mult), ('/', Div), ('(', Lp), (')', Rp)] 

tokenize :: String -> Either Error [Token] 
tokenize "" = Right [] 
tokenize (x:xs) = case lookup x tokenTable of 
    Just t -> fmap (t:) (tokenize xs) 
    Nothing -> recognize x where 
    recognize x 
     | isAlpha x = fmap (Var:) (tokenize xs) 
     | isDigit x = fmap (Const:) (tokenize xs) 
     | isSeparator x = fmap (Whitespace:) (tokenize xs) 
     | otherwise = Left "Cannot determine lexeme" 

然而,這很快就變得單調乏味。它已經是,不知何故,因爲我們必須使用fmap解除列表,請注意Either。想象一下你將如何實現指出錯誤的位置?進一步essentialy變成實現monad堆棧和重新實現一個解析器組合器,如Parsec。這就是爲什麼它經常推薦直接使用combinator庫,並且讓它執行lexing。

如果您不能或不想使用完整的Parsec,您自己實現basic functionality並不難。

0

您不需要一般分析空格。以下是您和phg的解決方案的組合:

import Data.Char 

data Token = Plus | Minus | Mult | Div | Lp | Rp | Var | Digit | Undefined 
    deriving Show 

tokenMap :: String -> Token 
tokenMap "+" = Plus 
tokenMap "-" = Minus 
tokenMap "*" = Mult 
tokenMap "/" = Div 
tokenMap "(" = Lp 
tokenMap ")" = Rp 
tokenMap [c] 
    | isAlpha c = Var 
    | isDigit c = Digit 
tokenMap _ = Undefined 

classify :: String -> [Token] 
classify = map tokenMap . words