Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Parsing 括号如何处理自定义数据类型?_Parsing_Haskell_Operators_Expression_Parentheses - Fatal编程技术网

Parsing 括号如何处理自定义数据类型?

Parsing 括号如何处理自定义数据类型?,parsing,haskell,operators,expression,parentheses,Parsing,Haskell,Operators,Expression,Parentheses,目前,我正在研究在Haskell中解析和显示表达式的问题 type Name = String data Expr = Val Integer | Var Name | Expr :+: Expr | Expr :-: Expr | Expr :*: Expr | Expr :/: Expr | Expr :%: Expr *Main> Val 2 :*:Val 2 :

目前,我正在研究在Haskell中解析和显示表达式的问题

type Name = String
data Expr = Val Integer
          | Var Name
          | Expr :+: Expr
          | Expr :-: Expr
          | Expr :*: Expr
          | Expr :/: Expr
          | Expr :%: Expr
*Main> Val 2 :*:Val 2 :+: Val 3 
((2*2)+3)
*Main> Val 2 :*:(Val 2 :+: Val 3) 
(2*(2+3))
这是我的数据类型Expr的代码,这是我如何定义show函数的:

instance Show Expr where
  show (Val x) = show x
  show (Var y) = y
  show (p :+: q) = par (show p ++ "+" ++ show q)
  show (p :-: q) = par (show p ++ "-" ++ show q)
  show (p :/: q) = par (show p ++ "/" ++ show q)
  show (p :*: q) = par (show p ++ "*" ++ show q)
  show (p :%: q) = par (show p ++ "%" ++ show q)

par :: String -> String
par s = "(" ++ s ++ ")"
后来我尝试将字符串输入转换为表达式,但遇到了以下问题:我不明白第二种情况下的括号是如何在Haskell中实现的

type Name = String
data Expr = Val Integer
          | Var Name
          | Expr :+: Expr
          | Expr :-: Expr
          | Expr :*: Expr
          | Expr :/: Expr
          | Expr :%: Expr
*Main> Val 2 :*:Val 2 :+: Val 3 
((2*2)+3)
*Main> Val 2 :*:(Val 2 :+: Val 3) 
(2*(2+3))
因此,对于如何将字符串中的括号转换为表达式,我有点困惑。目前,我正在使用以下函数进行解析,但目前,它只是忽略了括号,这不是预期的行为:

toExpr :: String -> Expr
toExpr str = f (lexer str) (Val 0)
   where 
    f [] expr = expr
    f (c:cs) expr
     |isAlpha (head c)  = f cs (Var c)
     |isDigit (head c)  = f cs (Val (read c))
     |c == "+"  = (expr :+: f cs (Val 0))
     |c == "-"  = (expr :-: f cs (Val 0))
     |c == "/"  = (expr :/: f cs (Val 0))
     |c == "*"  = (expr :*: f cs (Val 0))
     |c == "%"  = (expr :%: f cs (Val 0))
     |otherwise = f cs expr
编辑:很少有语法错误

我不明白第二种情况下的括号是如何在Haskell中实现的

type Name = String
data Expr = Val Integer
          | Var Name
          | Expr :+: Expr
          | Expr :-: Expr
          | Expr :*: Expr
          | Expr :/: Expr
          | Expr :%: Expr
*Main> Val 2 :*:Val 2 :+: Val 3 
((2*2)+3)
*Main> Val 2 :*:(Val 2 :+: Val 3) 
(2*(2+3))
括号只是优先于要分析的表达式的某个部分。问题不在于渲染的括号。我认为问题在于您没有为运算符指定优先级。这意味着除非您指定括号,否则Haskell将考虑所有操作符具有相同的优先级,并解析这些从左到右。这意味着x⊕ Y⊗ z被解析为(x)⊕ y)⊗ z

您可以使用
infixl
定义
:+:
:*
等运算符的优先级:

infixl 7 :*:, :/:, :%:
infixl 5 :+:, :-:

type Name = String
data Expr = Val Integer
          | Var Name
          | Expr :+: Expr
          | Expr :-: Expr
          | Expr :*: Expr
          | Expr :/: Expr
          | Expr :%: Expr

至于您的解析器(toExpr
),您将需要一个类似于a的解析机制,它将结果存储在堆栈上,从而进行正确的操作。

这是我最后一个解析器,它提供了我需要的结果。为了得到我想要的结果,我添加了正确的语法,并根据语法编写了一个语法分析。 谢谢大家的帮助

{-
  parser for the following grammar:
  E  -> T E'
  E' -> + T E' | - T E' | <empty string>
  T  -> F T'
  T' -> * F T' | / F T' | % F T' | <empty string>
  F  -> (E) | <integer> | <identifier> 
-}

parseExpr :: String -> (Expr,[String])
parseExpr tokens = parseE (lexer tokens)

parseE :: [String] -> (Expr,[String])
parseE tokens = parseE' acc rest where (acc,rest) = parseT tokens

parseE' :: Expr -> [String] -> (Expr,[String])
parseE' accepted ("+":tokens) = let (acc,rest) = parseT tokens in parseE' (accepted :+: acc) rest
parseE' accepted ("-":tokens) = let (acc,rest) = parseT tokens in parseE' (accepted :-: acc) rest
parseE' accepted tokens = (accepted,tokens)

parseT :: [String] -> (Expr,[String])
parseT tokens = let (acc,rest) = parseF tokens in parseT' acc rest

parseT' :: Expr -> [String] -> (Expr,[String])
parseT' accepted ("*":tokens) = let (acc,rest) = parseF tokens in parseT' (accepted :*: acc) rest
parseT' accepted ("/":tokens) = let (acc,rest) = parseF tokens in parseT' (accepted :/: acc) rest
parseT' accepted ("%":tokens) = let (acc,rest) = parseF tokens in parseT' (accepted :%: acc) rest
parseT' accepted tokens = (accepted,tokens)

parseF :: [String] -> (Expr,[String])
parseF ("(":tokens) = (e, tail rest) where (e,rest) = parseE tokens 
parseF (t:tokens)
  | isAlpha (head t) = (Var t,tokens)
  | isDigit (head t) = (Val (read t),tokens)
  | otherwise = error ""
parseF [] = error ""


lexer :: String -> [String]
lexer [] = []
lexer (c:cs)
  | elem c " \t\n"        = lexer cs   
  | elem c "=+-*/%()" = [c]:(lexer cs)
  | isAlpha c             = (c:takeWhile isAlpha cs):lexer(dropWhile isAlpha cs)
  | isDigit c             = (c:takeWhile isDigit cs):lexer(dropWhile isDigit cs)
  | otherwise             = error ""
{-
以下语法的语法分析器:
E->T E'
E'->+te'|-te'|
T->F T'
T'->*F T'|/F T'|%F T'|
F->(E)|
-}
parsexpr::String->(Expr,[String])
parsexpr令牌=parseE(lexer令牌)
parseE::[String]->(Expr[String])
parseE-tokens=parseE'acc-rest其中(acc,rest)=parseT-tokens
parseE'::Expr->[String]->(Expr[String])
parseE'accepted(“+”:tokens)=let(acc,rest)=在parseE'(accepted:+:acc)rest中解析令牌
parseE'accepted(“-”:tokens)=let(acc,rest)=parseE'(accepted:-:acc)rest中的parseT令牌
parseE'接受的令牌=(接受的,令牌)
语法分析器::[String]->(Expr[String])
parsettokens=let(acc,rest)=parsetacc rest中的parseF令牌
parseT'::Expr->[String]->(Expr[String])
parseT'accepted(“*”:tokens)=let(acc,rest)=parseT'(accepted::::acc)rest中的parseF令牌
parseT'accepted(“/”:tokens)=let(acc,rest)=parseT'(accepted:/:acc)rest中的parseF令牌
parseT'已接受(“%”:标记)=let(acc,rest)=parseT'(已接受:%:acc)rest中的parseF标记
parseT'accepted tokens=(accepted,tokens)
parseF::[String]->(Expr[String])
parseF(“(”:tokens)=(e,tail rest),其中(e,rest)=parseE tokens
parseF(t:tokens)
|isAlpha(头t)=(变量t,代币)
|isDigit(头t)=(Val(读取t),令牌)
|否则=错误“”
parseF[]=错误“”
lexer::String->[String]
lexer[]=[]
lexer(c:cs)
|元素c“\t\n”=词法器cs
|元素c“=+-*/%()”=[c]:(lexer-cs)
|isAlpha c=(c:takewhileisalpha cs):lexer(dropwhileisalpha cs)
|isdigitc=(c:takewhileisdigitcs):lexer(dropwhileisdigitcs)
|否则=错误“”

禁止固定性声明(使用
infixl
infixr
infix
),您的运算符都将具有优先级9(与
!!
相同)并且保持关联性。但是,这与您在解析语言中为运算符指定的优先级和关联性无关。
toExpr
函数可以以您想要的任何方式处理这些操作,而不管
:+:
和co的优先级或关联性如何。尽管如此,这不会影响
的结果>toExpr
,所以我认为这对OP的实际问题没有帮助。谢谢你的回答,但正如sepp2k提到的,不幸的是,它对我最初的问题没有帮助,因为即使在我的toExpr解析后添加了infixl,它仍然是从左到右解析的。@ArsenyNikonov:解析确实没有影响,因为你这样做了y、 我认为您应该在这里使用LL、LR或LALR解析器,该解析器使用堆栈作为中间结果。感谢您的建议,我将对此进行研究。