[英]Haskell: how to evaluate a String like "1+2"
實際上我有一些像"x + y"
這樣的公式,它是一個String
。 我設法將x/y
變量替換為特定值,例如"1.2"
,它仍然是String
類型。 現在我有像"1 + 2"
這樣的表達。
所以問題是如何評估一個字符串類型的表達式並得到結果。
ps:我想要read
之類的東西,它可以直接轉換整個字符串表達式,而不是逐個處理運算符(+/- 等)。 那可能嗎?
你的問題留下了很大的解釋空間。 我猜你不習慣建立整個lexing,解析,類型檢查和評估的整個流程。 很長的答案將涉及你定義你想要評估的語言(只是用'+'整數,也許所有的理性用'+',' - ''*','/',甚至更大的語言?)並執行每個語言對於該語言的上述步驟。
簡短的回答是:要評估Haskell表達式,其中包括您可能正在討論的基本數學運算符,只需使用“提示”包:
$ cabal install hint
...
$ ghci
> import Language.Haskell.Interpreter
> runInterpreter $ setImports ["Prelude"] >> eval "3 + 5"
Right "8"
好極了!
可能值得閱讀真實世界Haskell的Parsec部分。 您可以將其解析為表達式樹,然后替換值。當您使用Parsec時,您將使用類型構建表達式樹(非常粗略,我確定我犯了一些錯誤,我將在修復程序中編輯當人們指出他們的時候!)就像下面那樣。
data Op = Plus | Minus
data Term = Variable String
| Value Int
data Expression = Expr Expression Op Expression
| Term
然后1 + 2將是(Expr (Variable "x") Plus (Variable "y"))
並且您可以應用適當的替換。
為了得到結果,我想你可以正確一個簡單的函數evaluate :: Map String Int -> Expression -> Either ErrorMessage Int
,它將在地圖中應用綁定,然后在可能的情況下計算結果。
好吧,我一直在反對暗示,但我現在放棄了。 我知道提示可以做到這一點,但我不知道如何。 [編輯] 請參閱TomMD關於如何為提示設置導入的答案。 [/編輯]
import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError)
main = do let resIO = eval "3" :: Interpreter String
res <- runInterpreter resIO
print res
這無趣地產生了Right "3"
的結果。 我嘗試了以下變種,只是遇到了令人困惑的錯誤:
... eval "3 + 3" ....
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"])
+
運算符不在范圍內??? WTF ...
import Language.Haskell.Interpreter (interpret, as, runInterpreter, Interpreter)
main = do let resIO = interpret "3" (as :: Int) :: Interpreter Int
res <- runInterpreter resIO
print res
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: type constructor or class 'Int'")])
Int
類不在范圍內??? 啊...
我邀請那些比我更有知識的人來闡述提示的細節。
接受的答案顯示了使用hint的最小示例,但它缺少一些東西:
let x = 1 in x + 1
之類的綁定進行評估。這是一個更完整的例子:
import qualified Control.DeepSeq as DS
import Control.Exception (ArithException (..))
import qualified Control.Exception as Ex
import qualified Control.Monad as M
import qualified Data.Either as E
import qualified Language.Haskell.Interpreter as I
evalExpr :: String -> [(String, Integer)] -> IO (Maybe Integer)
evalExpr expr a = Ex.handle handler $ do
i <- I.runInterpreter $ do
I.setImports ["Prelude"]
-- let var = value works too
let stmts = map (\(var, val) -> var ++ " <- return " ++ show val) a
M.forM_ stmts $ \s -> do
I.runStmt s
I.interpret expr (I.as :: Integer)
-- without force, exception is not caught
(Ex.evaluate . DS.force) (E.either (const Nothing) Just i)
where
handler :: ArithException -> IO (Maybe Integer)
handler DivideByZero = return Nothing
handler ex = error $ show ex
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.