Haskell: how to evaluate a String like "1+2"
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.
Related videos on Youtube
yoz
Updated on October 25, 2020Comments
-
yoz over 3 years
Actually I have some formula like
"x + y"
, which is aString
. I managed to replace thex/y
variable with specific values like"1.2"
, which is stillString
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 about 13 yearsOf 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 about 13 yearsI think @yoz expected something more of an inbuilt function
eval :: String -> Double
. A little more haskellish would perhaps beeval :: 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 about 13 yearsYou need to
setImports
, see my answer. -
yoz about 13 yearsI 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 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 about 10 yearsAny way to do this with standard Haskell, without installing
hint
? -
Thomas M. DuBuisson about 10 yearsGlasgow 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..