我已经创建了一个自定义数据类型Expr
type Name = String
type Domain = [Integer]
data Expr = Val Integer
| Var Name
| Expr :+: Expr
| Expr :-: Expr
| Expr :*: Expr
| Expr :/: Expr
| Expr :%: Expr
deriving Eq
我需要创建一个解析器,在不使用Haskell中的解析器库的情况下从字符串创建数据类型Expr。
我为初始字符串创建了解析器,该字符串接受“2 * a + b”形式的字符串并将其转换为“Val 2:*:Var”形式“:+:Var”b“ “这是Expr接受的,但这是我不知道要做的事情,以便更进一步。我的问题是我不知道如何在没有解析器库的情况下从这样的字符串创建Expr。
答案 0 :(得分:1)
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