簡體   English   中英

Haskell:如何評估像“1+2”這樣的字符串

[英]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"

好極了!

可能值得閱讀真實世界HaskellParsec部分。 您可以將其解析為表達式樹,然后替換值。當您使用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的最小示例,但它缺少一些東西:

  1. 如何使用let x = 1 in x + 1之類的綁定進行評估。
  2. 如何處理異常,具體除以零。

這是一個更完整的例子:

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM