List Haskell中的中缀到后缀形式
我是Haskell的初学者,我对如何使这个程序工作有些迷茫。我要做的是得到一个像这样的字符串:“a+(b/c)”,然后把它转换成后缀形式,就像这样:“abc/+” 这个问题还说我不能用下面的词:“words,putStr,putStrLn,readLn,print” 首先,我设法将字母从符号中分离出来,然后将它们组合在一起:List Haskell中的中缀到后缀形式,list,algorithm,haskell,postfix-notation,infix-notation,List,Algorithm,Haskell,Postfix Notation,Infix Notation,我是Haskell的初学者,我对如何使这个程序工作有些迷茫。我要做的是得到一个像这样的字符串:“a+(b/c)”,然后把它转换成后缀形式,就像这样:“abc/+” 这个问题还说我不能用下面的词:“words,putStr,putStrLn,readLn,print” 首先,我设法将字母从符号中分离出来,然后将它们组合在一起: isLetter :: String -> String isLetter [] = [] isLetter (a:as) | a `elem` "abcd
isLetter :: String -> String
isLetter [] = []
isLetter (a:as) | a `elem` "abcdefghijklmnopqrstuvwxyz" = a : isLetter as
| otherwise = isLetter as
isOperator :: String -> String
isOperator [] = []
isOperator (a:as) | a `elem` "+-*/^" = a : isOperator as
| otherwise = isOperator as
onp :: String -> String
onp [] = []
onp str = isLetter str ++ isOperator str
问题在于,它只是将操作员放在字母后面,而不考虑它实际应该遵循的顺序
所以我做了一些关于如何转换它的研究,我认为我应该首先检查哪个是运算符,哪个是字母,根据将中缀转换为后缀的规则,我将把它们放在另一个字符串中。所以我创建了两个函数来判断它是字母还是运算符
这是一片混乱,但它是这样的:
isLetHelp :: Char -> Bool
isLetHelp ch | ch `elem` "abcdefghijklmnopqrstuvwxyz" = True
| otherwise = False
isOpHelp :: Char -> Bool
isOpHelp a | a `elem` "()+-*/^" = True
| otherwise = False
isOperator :: String -> String
isOperator [] = []
isOperator (a:as) | a `elem` "+-*/^" = a : isOperator as
| otherwise = isOperator as
getSymbol :: String -> String
getSymbol [] = []
getSymbol (a:as) | isOpHelp == True = isOperator
| isLetHelp == True = a : getSymbol as
最后一个函数“getSymbol”将负责获取符号并以正确的方式组织它们,但我不知道如何做。从您的示例中不清楚
a+(b/c)
,但我假设您需要考虑运算符优先级,以便a+b/c
解析为a+(b/c)
(不是(a+b)/c
),因此也计算为abc/+
(而不是ab+c/
)
可能有更简单或更惯用的方法来实现这一点,但作为一项教育任务,这是学习如何使用基本递归函数的一个好方法。以这种方式解决此任务的主要方法有两种:
- ,它专门用于将中缀转换为后缀
type ShuntingYardState = ([Char], [Char])
要将一个元素推送到堆栈或将输出中的一个元素排队,您将把它放在列表的前面;要从堆栈中弹出一个元素,您可以使用模式匹配。输出队列严格地说是结果的累加器;我们从不从中出列
要将中缀表达式字符串转换为后缀,请使用空运算符堆栈和空输出队列的初始状态启动此算法:
expression :: String -> String
expression input = shuntingYard ([], []) input
variable :: Char -> ShuntingYardState -> ShuntingYardState
算法本身有五种主要情况和一种错误情况供您处理:
shuntingYard
:: ShuntingYardState
-> String
-> String
shuntingYard
state@(operatorStack, outputQueue)
(current : rest)
-- 1. A variable term: push it to the output and proceed.
| isVariable current
= shuntingYard (variable current state) rest
-- 2. An operator: process operator precedence and proceed.
| isOperator current
= shuntingYard (operator current state) rest
-- 3. A left parenthesis: push it onto the operator stack.
| current == '('
= shuntingYard (leftParenthesis state) rest
-- 4. A right parenthesis: process grouping and proceed.
| current == ')'
= shuntingYard (rightParenthesis state) rest
-- 5. An unrecognized token: raise an error.
| otherwise
= error $ "unrecognized input: " ++ show rest
-- 6. No more input: finalize the result.
shuntingYard state []
= endOfInput state
isolp
:
isVariable :: Char -> Bool
isOperator :: Char -> Bool
expression :: String -> String
expression input = shuntingYard ([], []) input
variable :: Char -> ShuntingYardState -> ShuntingYardState
^
),或优先级高于或等于当前标记(对于左关联运算符,如*
和-
)。在第二种情况下,它只是将当前运算符标记推送到运算符堆栈
operator :: Char -> ShuntingYardState -> ShuntingYardState
operator current (op : operatorStack, outputQueue)
| op /= '('
, … -- Compare precedence & associativity.
= operator … -- Repeat.
operator current (operatorStack, outputQueue)
= … -- Push the operator and return.
leftParenthesis :: ShuntingYardState -> ShuntingYardState
operator :: Char -> ShuntingYardState -> ShuntingYardState
operator current (op : operatorStack, outputQueue)
| op /= '('
, … -- Compare precedence & associativity.
= operator … -- Repeat.
operator current (operatorStack, outputQueue)
= … -- Push the operator and return.
leftParenthesis :: ShuntingYardState -> ShuntingYardState
rightParenthesis :: ShuntingYardState -> ShuntingYardState
rightParenthesis (op : operatorStack, outputQueue)
| op /= '('
= rightParenthesis … -- Move operator to output.
| otherwise
= … -- Reached matching left parenthesis; return.
rightParenthesis ([], outputQueue)
= … -- Mismatched right parenthesis; error.
endOfInput
:: ShuntingYardState
-> String
endOfInput ([], outputQueue)
= … -- Success! Return the final result.
endOfInput (op : operatorStack, outputQueue)
| op == '('
= … -- Mismatched left parenthesis; error.
| otherwise
= … -- Operator remaining; move to output and repeat.
rightParenthesis :: ShuntingYardState -> ShuntingYardState
rightParenthesis (op : operatorStack, outputQueue)
| op /= '('
= rightParenthesis … -- Move operator to output.
| otherwise
= … -- Reached matching left parenthesis; return.
rightParenthesis ([], outputQueue)
= … -- Mismatched right parenthesis; error.
endOfInput
:: ShuntingYardState
-> String
endOfInput ([], outputQueue)
= … -- Success! Return the final result.
endOfInput (op : operatorStack, outputQueue)
| op == '('
= … -- Mismatched left parenthesis; error.
| otherwise
= … -- Operator remaining; move to output and repeat.
执行此技术的标准方法是使用。也许Wikipedia页面可以为您指出正确的方向。提供的伪代码是必需的(因此更适合Python之类的东西),但实际上在Haskell中更容易,因为它是一种非常以解析器为中心的技术。@SilvioMayolo哦,我读了一些关于它的内容。我会看一看。谢谢!哦,老兄,这是一个多么好的答案。解释得太好了。我还在处理如何做,但我知道我现在可以做了。谢谢!你能告诉我“状态”是什么吗在调车场函数中?@RhynoProgrammin-此
状态@(operatorStack,outputQueue)
结构允许您将整个(对)参数称为state
,并将其组件称为operatorStack
和outputQueue
。称为“模式匹配”。关于另一个SO问题的更多详细信息: