我的作业是在Haskell中创建一个表达式解析器。我之前的问题是关于在Haskell中解析SO的问题,我找不到我的案例的帮助。
表达式定义如下:
data Expr =
| Const Int
| Var String
| Add Expr Expr | Sub Expr Expr | Mul Expr Expr | Pow Expr Int
deriving Show
类型Parser
定义如下:
type Parser a = String -> Maybe (a, String)
我的作业中提供的解析器定义如下:
--Primitive parsers
success :: a -> Parser a
success v = \inp -> Just (v, inp)
failure :: Parser a
failure = \_ -> Nothing
item :: Parser Char
item = \inp -> case inp of
"" -> Nothing
(c : cs) -> Just (c, cs)
--Sequential parsers
(>>>) :: Parser a -> (a -> Parser b) -> Parser b
p >>> f = \inp -> case p inp of
Nothing -> Nothing
Just (x, cs) -> f x cs
(&&&) :: Parser a -> Parser b -> Parser b
p &&& q = p >>> \_ -> q
-- Conditional Parsers
sat :: (Char -> Bool) -> Parser Char
sat f = item >>> \c -> if f c then success c else failure
digit :: Parser Char
digit = sat isDigit
space :: Parser Char
space = sat isSpace
char :: Char -> Parser Char
char c = sat (== c)
-- Alternative parsers
(+++) :: Parser a -> Parser a -> Parser a
p +++ q = \inp -> case p inp of
Nothing -> q inp
Just res -> Just res
-- Iterative Parsers
many :: Parser a -> Parser [a]
many p = many1 p +++ success []
many1 :: Parser a -> Parser [a]
many1 p = p >>> \v -> many p >>> \vs -> success (v : vs)
--Token
nat :: Parser Int
nat = many1 digit >>> \cs -> success (read cs)
spaces :: Parser ()
spaces = many space &&& success ()
token :: Parser a -> Parser a
token p = spaces &&& p
natural :: Parser Int
natural = token nat
symbol :: Char -> Parser Char
symbol c = token (char c)
现在我必须开发一个expr
函数,该函数需要String
并将其转换为Expr
。
为了在我的作业中做到这一点,我发现已经定义了如下函数:
expr :: Parser Expr
expr = term >>> \t -> (symbol '+' &&& expr >>> \e -> success $ Add t e) +++ (symbol '-' &&& expr >>> \e -> success $ Sub t e) +++ success t
我知道我必须开发三个功能:term
,power
和factor
。
函数factor
应解析常量或变量。
函数term
应解析单个factor
(例如2
)或两个factor
之间的乘法(例如2*x
)。
我不太了解monad是如何工作的,我在做作业时遇到了问题。有关如何编写这些函数的任何帮助吗?
这是我在作业中找到的图像。
答案 0 :(得分:2)
您需要编写的各种解析器正在将算术运算顺序的优先级规则构建到解析器的结构中。从大多数到最不重要的顺序,这些是
factor
power
term
expr
。您从外部开始使用具有最低优先级的运算符,并使用具有最高优先级的运算符。进入乘法,您可以像编写term
一样编写expr
。 expr
由term
组成; term
将包含power
s
term :: Parser Expr
term = power >>> \p -> (symbol '*' &&& term >>> \e -> success $ Mul p e) +++ success p
同样,power
将由factor
组成。由于Pow
的右侧是Int
,因此它只使用自然数nat
而不是递归。
power :: Parser Expr
power = factor >>> f -> (symbol '^' &&& nat >>> \n -> success $ Pow f n) +++ success f
我会为你写factor
;我写的部分与expr
几乎相同,你已经想到了。 factor
中的括号将包含任意表达式expr
,在外部以最小优先级重新开始。这样您就可以解析"2*(x+1)"