如果你真的只需要一個標記器,下面是如何在沒有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並不難。
來源
2013-11-28 23:30:12
phg