Evaluating arithmetic expressions at run time

Haskell beginner using GHC. I have a function to do some simple arithmetic at run time: myeval :: Int -> Int -> String -> Int myeval x y "+" = (+) x y myeval x y "-" = (-) x y myeval x y "*" = (*) x y -- ... While that works, I'm curious to know if it can be done more elegantly. I'm thinking of something like: myeval :: Int -> Int -> String -> Int myeval x y op = (read op) x y Thanks, /-\ ____________________________________________________ Do you Yahoo!? Listen to over 20 online radio stations and watch the latest music videos on Yahoo! Music. http://au.launch.yahoo.com

Andrew Savige wrote:
Haskell beginner using GHC. Hello there!
How about, opTable = [ ("+", (+)) , ("-", (-)) ... ] myeval x y op = let Just fun = lookup op opTable in x `fun` y ?
I have a function to do some simple arithmetic at run time:
myeval :: Int -> Int -> String -> Int myeval x y "+" = (+) x y myeval x y "-" = (-) x y myeval x y "*" = (*) x y -- ...
While that works, I'm curious to know if it can be done more elegantly. I'm thinking of something like:
myeval :: Int -> Int -> String -> Int myeval x y op = (read op) x y
Thanks, /-\
____________________________________________________ Do you Yahoo!? Listen to over 20 online radio stations and watch the latest music videos on Yahoo! Music. http://au.launch.yahoo.com _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

BTW: There isn't an easy way to magically derive opTable. We're relying on the fact that these simple functions all have the same type. Ben Lippmeier wrote:
opTable = [ ("+", (+)) , ("-", (-)) ... ]
myeval x y op = let Just fun = lookup op opTable in x `fun` y
You could also do myeval x y op = case op of "+" -> x + y "-" -> x - y ... is probably the "smallest" way. Ben.

On 28/01/06, Andrew Savige
Haskell beginner using GHC.
I have a function to do some simple arithmetic at run time:
myeval :: Int -> Int -> String -> Int myeval x y "+" = (+) x y myeval x y "-" = (-) x y myeval x y "*" = (*) x y -- ...
While that works, I'm curious to know if it can be done more elegantly. I'm thinking of something like:
myeval :: Int -> Int -> String -> Int myeval x y op = (read op) x y
Thanks, /-\
Apart from moving to a lookup Map or something, a simple reordering of the arguments allows you to shorten things up a bit: myeval :: String -> Int -> Int -> Int myeval "+" = (+) myeval "-" = (-) myeval "*" = (*) etc. - Cale

--- Cale Gibbard wrote:
Apart from moving to a lookup Map or something, a simple reordering of the arguments allows you to shorten things up a bit:
myeval :: String -> Int -> Int -> Int myeval "+" = (+) myeval "-" = (-) myeval "*" = (*) etc.
Thanks to all for the excellent suggestions. I'm liking the Haskell version of this function a lot more now. :-) To help me learn Haskell, I'm converting a small Ruby program to Haskell. In Ruby this can be done in one line: def myeval(x, y, op) x.send op, y end I had a feeling this sort of dynamic sending of messages to objects at run time was impossible in Haskell, hence my question. What I'm still unsure about is why this sort of thing is impossible in Haskell. Is it a fair comment to state that this sort of thing is impossible in Haskell as a consequence of its static typing? Or could it be done in a static typed language with more run time support? Despite being longer, overall I prefer the Haskell version because it is faster and "safer" (in that a number of run time errors in the Ruby version are caught at compile time in the Haskell version). /-\ ____________________________________________________ Do you Yahoo!? Find a local business fast with Yahoo! Local Search http://au.local.yahoo.com

Andrew Savige wrote:
--- Cale Gibbard wrote:
Apart from moving to a lookup Map or something, a simple reordering of the arguments allows you to shorten things up a bit:
myeval :: String -> Int -> Int -> Int myeval "+" = (+) myeval "-" = (-) myeval "*" = (*) etc.
Thanks to all for the excellent suggestions. I'm liking the Haskell version of this function a lot more now. :-)
To help me learn Haskell, I'm converting a small Ruby program to Haskell. In Ruby this can be done in one line:
def myeval(x, y, op) x.send op, y end
This could be done in Haskell by myeval :: a->b->(a -> b -> c) -> c myeval x y op = op x y eg myeval (+) 1 2 Regards, Brian.

Brian Hulley wrote:
eg myeval (+) 1 2
myeval 1 2 (+) -- I *always* seem to make at least one mistake per post ;-) (I originally wrote the code to take the op first, which is the usual Haskell convention so that you can do useful things with (myeval someop) but then I noticed you had the op arg last in your Ruby example so I changed the code but forgot to change my example...)

--- Brian Hulley wrote:
def myeval(x, y, op) x.send op, y end
This could be done in Haskell by
myeval :: a->b->(a -> b -> c) -> c myeval x y op = op x y
eg myeval (+) 1 2
Though the following program does indeed work: myeval :: (Int -> Int -> Int) -> Int -> Int -> Int myeval op x y = op x y main :: IO () main = do putStrLn $ show (myeval (+) 2 3) I can't hardwire (+) because the operator is unknown at compile time; it is input to the program at run time as a string ("+" in this example). My problem is how to convert the string "+" to the operator (+) at run time. Well, I could do it with a lookup table: mycvt :: String -> (Int -> Int -> Int) mycvt "+" = (+) mycvt "-" = (-) mycvt "*" = (*) but that is what I'm trying to avoid (I was naively hoping that the read function could magically do it somehow :-). /-\ Send instant messages to your online friends http://au.messenger.yahoo.com

On 1/28/06, Andrew Savige
--- Brian Hulley wrote:
def myeval(x, y, op) x.send op, y end
This could be done in Haskell by
myeval :: a->b->(a -> b -> c) -> c myeval x y op = op x y
eg myeval (+) 1 2
Though the following program does indeed work:
myeval :: (Int -> Int -> Int) -> Int -> Int -> Int myeval op x y = op x y
main :: IO () main = do putStrLn $ show (myeval (+) 2 3)
I can't hardwire (+) because the operator is unknown at compile time; it is input to the program at run time as a string ("+" in this example).
My problem is how to convert the string "+" to the operator (+) at run time. Well, I could do it with a lookup table:
mycvt :: String -> (Int -> Int -> Int) mycvt "+" = (+) mycvt "-" = (-) mycvt "*" = (*)
but that is what I'm trying to avoid (I was naively hoping that the read function could magically do it somehow :-).
It's probably a bit more heavy-weight than what you were looking for, but take a look at: http://www.cse.unsw.edu.au/~dons/hs-plugins/ It allows you to load and execute Haskell code at run-time. I suppose this should also be possible by importing some part of GHC (perhaps GHCi). /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

Hello Andrew, Saturday, January 28, 2006, 1:38:08 PM, you wrote: AS> def myeval(x, y, op) AS> x.send op, y AS> end AS> I had a feeling this sort of dynamic sending of messages AS> to objects at run time was impossible in Haskell, hence AS> my question. What I'm still unsure about is why this sort AS> of thing is impossible in Haskell. Is it a fair comment AS> to state that this sort of thing is impossible in Haskell AS> as a consequence of its static typing? Or could it be done AS> in a static typed language with more run time support? it's because Haskell is compiled laguage and in compiled program "a+b" represented just by asm instructions and don't had any link with the string "+". To have such link it's necessary to had run-time typing information, and current Haskell implementations has that in the module Data.Dynamics. but even this information in current state don't know anything about "+" and other operations, it is only informatio about types itself. so, the anser: that can be done, but there is no much need in it. on the other side, there is a huge area of "generic programming" techniques that is something like to run-time investigation of type structure, that is available in Ruby. using this one can, for example, traverse some complex data structure that uses hundreds of different types, and replace, say, only Int's with another values. Data.Dynamics is for such types of tasks AS> Despite being longer, overall I prefer the Haskell version AS> because it is faster and "safer" (in that a number of run AS> time errors in the Ruby version are caught at compile time AS> in the Haskell version). yes, and that is unvaluable for real-world large projects -- Best regards, Bulat mailto:bulatz@HotPOP.com

On Sat, 28 Jan 2006, Andrew Savige wrote:
Haskell beginner using GHC.
I have a function to do some simple arithmetic at run time:
myeval :: Int -> Int -> String -> Int myeval x y "+" = (+) x y myeval x y "-" = (-) x y myeval x y "*" = (*) x y -- ...
Additionally to the other suggestions, I advise using a custom type data Op = Add | Sub | Mul instead of String, if possible.
participants (7)
-
Andrew Savige
-
Ben Lippmeier
-
Brian Hulley
-
Bulat Ziganshin
-
Cale Gibbard
-
Henning Thielemann
-
Sebastian Sylvan