import Control.Applicative (Alternative (empty, many, some, (<|>)), (<**>))
import Data.Char (isSpace, isDigit)
import Data.Maybe (listToMaybe)
編寫一個基本低效的解析庫實際上並不難,可以在50行以下的代碼中完成。核心類型如下:
newtype Parser a = Parser (String -> [(a, String)])
parse :: Parser a -> String -> Maybe a
parse (Parser p) s = listToMaybe $ fst <$> p s
這個解析器部分消耗一個字符串,其餘串一併返回解析後的結果a
。但是可能有很多解析方案,這就是爲什麼它返回結果和剩餘部分的列表。
對於使用這種類型,我們需要一些更多的實用程序。我離開了_
供您實施。
instance Functor Parser where
fmap (Parser p) = _
instance Applicative Parser where
pure a = Parser $ \s -> (a, s) -- Consumes nothing and returns a
Parser pf <*> Parser pa = _ -- Parse pf, then parse pa and apply the result
-- of pf to that of pa.
instance Alternative Parser where
empty = Parser $ \s -> [] -- Matches nothing
Parser p1 <|> Parser p2 = _ -- Matches either p1 or if that fails p2.
satisfy :: (Char -> Bool) -> Parser Char
satisfy = _
space :: Parser()
space =() <$ satisfy isSpace
spaces :: Parser()
spaces =() <$ many space
char :: Char -> Parser Char
char c = satisfy (c ==)
-- | Detects the end of file.
eof :: Parser()
eof = _
-- | Succeeds when at the end of a word, without consuming any input
eow :: Parser()
eow = _
現在我們可以繼續使用這個解析器像任何遞歸下降解析器:
data Expr = Val Integer
| Expr :*: Expr
| Expr :+: Expr
deriving Show
parseVal :: Parser Expr
parseVal =
char '(' *> parseAdd <* char ')' <|>
Val . read <$> some (satisfy isDigit) <* eow
parseMul :: Parser Expr
parseMul = _
parseAdd :: Parser Expr
parseAdd = _
parseExpr :: Parser Expr
parseExpr = parseAdd <* eof
爲什麼你不希望使用解析庫? – melpomene
因爲我不被允許使用它。 –
這個作業練習的約束是什麼? – melpomene