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

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?


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!


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.


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.