Haskell:如何计算字符串“1+2”

y1aodyip  于 2023-01-26  发布在  其他
关注(0)|答案(4)|浏览(153)

实际上,我有一些公式,比如"x + y",它是String。我设法将x/y变量替换为特定的值,比如"1.2",它仍然是String类型。现在我有了"1 + 2"这样的表达式。
所以问题是如何计算一个字符串类型的表达式并得到结果。
ps:我想要read这样的东西,可以直接转换整个字符串表达式,而不是逐案处理运算符(+/-等),这可能吗?

hmmo2u0o

hmmo2u0o1#

你的问题给解释留下了很大的空间。我猜你还不习惯构建词法分析、解析、类型检查和求值的整个管道。详细的答案将包括定义你希望求值的语言(只使用带"+"的整数,也可以使用所有带"+"、"-"、"*"、"/"的有理数,甚至更大的语言?),然后为该语言执行上述每个步骤。
简短的回答是:要计算Haskell表达式,其中包含了你可能正在讨论的基本数学运算符,只需使用"hint"包:

$ cabal install hint
...
$ ghci
> import Language.Haskell.Interpreter
> runInterpreter $ setImports ["Prelude"] >> eval "3 + 5"
Right "8"

耶!

n3ipq98p

n3ipq98p2#

也许值得一阅读Real World 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,它将应用Map中的绑定,然后计算结果(如果可能的话)。

kuarbcqp

kuarbcqp3#

我一直在努力尝试hint,但现在我给予了。我知道hint可以做到这一点,但我不确定如何做到。[edit]***关于如何为hint设置导入,请参阅TomMD的答案。***[/edit]

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类不在范围内???啊...
我邀请那些比我更有知识的人来详细阐述暗示的细节。

bejyjqdl

bejyjqdl4#

可接受的答案显示了一个使用hint的最小示例,但缺少以下几点:
1.如何使用绑定(如let x = 1 in x + 1)进行计算。
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

相关问题