我正在嘗試為以下遞回資料型別制作決議器:
data Expr = Val Int
| Var Char
| App Op Expr Expr
deriving Show
data Op = Add | Sub | Mul | Div
deriving Show
例如,它應該決議"(1 (a / -2))"為App Add (Val 1) (App Div (Var 'a') (Val (-2))). 我已經設法為Val和Var建構式以及為Op的建構式撰寫決議器,如下所示:
import Text.Regex.Applicative
import Data.Char
rNonnegativeIntegral :: (Read a, Integral a) => RE Char a
rNonnegativeIntegral = read <$> some (psym isDigit)
rNegativeIntegral :: (Read a, Integral a) => RE Char a
rNegativeIntegral = negate <$> (sym '-' *> rNonnegativeIntegral)
rIntegral :: (Read a, Integral a) => RE Char a
rIntegral = rNonnegativeIntegral <|> rNegativeIntegral
rVal :: RE Char Expr
rVal = Val <$> rIntegral
rVar :: RE Char Expr
rVar = Var <$> psym isAlpha
rOp = aux <$> (foldr1 (<|>) $ map sym " -*/")
where
aux ' ' = Add
aux '-' = Sub
aux '*' = Mul
aux '/' = Div
當它加載到 ghci 時,它可以產生以下輸出:
ghci> findLongestPrefix rVal "-271"
Just (Val (-271), "")
ghci> findLongestPrefix rVar "a"
Just (Var 'a', "")
ghci> findLongestPrefix rOp "-"
Just (Sub, "")
當我為App建構式引入這個遞回定義時,麻煩就來了:
whiteSpace :: RE Char String
whiteSpace = many $ psym isSpace
strictWhiteSpace :: RE Char String
strictWhiteSpace = some $ psym isSpace
rApp :: RE Char Expr
-- flip App :: Expr -> Op -> Expr
-- strictWhiteSpace after rOp to avoid conflict with rNegativeInteger
rApp = flip App <$> (sym '(' *> whiteSpace *> rExpr)
<*> (whiteSpace *> rOp <* strictWhiteSpace)
<*> (rExpr <* whiteSpace <* sym ')')
rExpr :: RE Char Expr
rExpr = rVal <|> rVar <|> rApp
這很好地加載到 ghci,并且所有以前的建構式仍然有效。但是findLongestPrefix rApp "(1 a)",許多類似的運算式會導致 ghci 掛起并且不產生任何輸出。
通過實驗,我發現問題通常rExpr在作為第一個引數傳入時發生<*。例如,findLongestPrefix (rExpr <* whiteSpace) "a)"也會導致 ghci 掛起。
此外,當 for 的定義rExpr被替換為
rExpr = rVal <|> rVar
所有這些懸而未決的問題都會消失。"(1 a)"可以決議像這樣的簡單運算式,但不支持遞回運算式。
如何在不掛起問題的情況下在這里實作遞回決議器?
uj5u.com熱心網友回復:
您描述的運算式語言不規則。所以你必須使用不同的庫。
幸運的是,基本上相同的決議器結構應該適用于大多數其他決議器組合器庫。它應該像用新庫的名稱替換一些基本決議器來代替它們的正則運算式應用類似物一樣簡單。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/373182.html
下一篇:多行到PHP關聯陣列
