Haskell: how to evaluate a String like "1+2"

11,082

Solution 1

Your question leaves a lot of room for interpretation. I'm taking a guess you aren't accustom to building a whole pipeline of lexing, parsing, maybe type checking, and evaluating. The long answer would involve you defining what language you wish to evaluate (Just integers with '+', perhaps all rationals with '+', '-' '*', '/', or even a larger language?) and perform each of the above steps for that language.

The short answer is: to evaluate Haskell expressions, which includes the basic math operators you're probably talking about, just use the "hint" package:

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

Yay!

Solution 2

Might be worth reading the Parsec section of Real World Haskell. You could parse it into an expression tree and then substitute the values in. As you use Parsec you'd build up an expression tree using types (very roughly, I'm sure I've made some mistakes which I'll edit in fixes for as and when people point them out!) like that below.

 data Op = Plus | Minus
 data Term = Variable String
           | Value Int
 data Expression = Expr Expression Op Expression
                 | Term

Then 1 + 2 would be (Expr (Variable "x") Plus (Variable "y")) and you could apply the appropriate substitutions.

To get the result, I guess you could right a simple function evaluate :: Map String Int -> Expression -> Either ErrorMessage Int which would apply the bindings in the map and then calculate the result if possible.

Solution 3

Well I've been banging my head against hint but I give up for now. I know hint can do this but I'm not sure how. [edit] See TomMD's answer for how to set imports up for hint. [/edit]

import Language.Haskell.Interpreter (eval, runInterpreter, Interpreter, InterpreterError)

main = do let resIO = eval "3" :: Interpreter String
          res <- runInterpreter resIO
          print res

This uninterestingly produces Right "3" as the result. I tried the following variants, only to run into baffling errors:

... eval "3 + 3" ....
-- yields --
Left (WontCompile [GhcError (errMsg = "Not in scope: `+'"])

The + operator isn't 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'")])

The Int class isn't in scope??? ugh...

I invite those more knowledgeable than me to expound on the finer details of hint.

Share:
11,082

Related videos on Youtube

yoz
Author by

yoz

Updated on October 25, 2020

Comments

  • yoz
    yoz over 3 years

    Actually I have some formula like "x + y", which is a String. I managed to replace the x/y variable with specific values like "1.2", which is still String type. Now I have expression like "1 + 2".

    So the problem is how to evaluate a expression of a string type and get the result.

    ps: I wanna sth like read, that can directly convert the whole string expression instead of handling the operator (+/-,etc) case by case. Is that possible?

    • Ingo
      Ingo about 13 years
      Of course, it is possible. But I feel that you should use a better representation for expressions. One clue may be your phrase "convert the whole string expression". The question is: convert to what?
  • Tarrasch
    Tarrasch about 13 years
    I think @yoz expected something more of an inbuilt function eval :: String -> Double. A little more haskellish would perhaps be eval :: String -> Either ErrorMessage Double. However, as most have pointed out: Expressions represented as strings is bad. Better use a syntax tree like Jeff showed.
  • Thomas M. DuBuisson
    Thomas M. DuBuisson about 13 years
    You need to setImports, see my answer.
  • yoz
    yoz about 13 years
    I was trying to find a way to evaluate a String expression without lexical analysis, grammar definitions etc. C# can achieve this by compiling code at runtime. So actually I was just wondering whether there's sth similar in Haskell. Your answer is exactly what I need. Thank a lot~
  • Thomas M. DuBuisson
    Thomas M. DuBuisson about 13 years
    @yoz Glad I could help. Obviously you can read the haddock documents yourself, but really quickly the interpret function will give you a result of polymorphic type (not a string representation), which might be even better depending on your needs. Happy hacking.
  • vikingsteve
    vikingsteve about 10 years
    Any way to do this with standard Haskell, without installing hint ?
  • Thomas M. DuBuisson
    Thomas M. DuBuisson about 10 years
    Glasgow Haskell provides an API, which is what hint uses. Otherwise (with pure Haskell as appears in the spec) you are out of luck and must write an interpreter or other custom solution..

Related