how to make an eval function?
Thanks for fe -- a very nice tiny interpreter.
How could I make an eval function (or macro)? i.e. such that
(= a '(+ 1 2))
(eval a) => 3
I tried using mac and fn but couldn't make it. Did I miss something obvious?
Here's how I did it:
- In
fe.c, at line 44, add a new primitive typeP_EVALto theenum. You can insert it anywhere before the final field,P_MAX. - In
fe.c, at line 50, add the string name forP_EVALas"eval". N.B. you need to insert the string at the matching index based on the value of theenumfield you just added. - In
fe.c, at line 634, add this code:
case P_EVAL:
va = checktype(ctx, evalarg(), FE_TPAIR);
res = eval(ctx, va, env, NULL);
break;
You now have a functional eval primitive. The following scheme code should work:
(print "(eval '(+ 100 200)) =" (eval '(+ 100 200)))
(do
(let expr '(for x (list 1 2 3 4 5)
(print "x =" x)))
(print "(eval expr) =" (eval expr)))
Keep in mind that fe doesn't support tail call optimization. This implementation of the eval primitive invokes two peer recursive calls to the C eval function.
Thanks for your solution!
Any chance the original author (rxi) would include it in 'fe'?
I realized this well after my last post, but I sort of over fitted my implementation to your example. You can simplify the case statement I provided:
case P_EVAL:
res = eval(ctx, EVAL_ARG(), env, NULL);
break;
The prior version would only evaluate function application. This version will dynamically evaluate any legitimate s-expression. For example:
(do
(let a 42)
(print "(eval 'a) =" (eval 'a)))
Now works, evaluating the variable. Either version works, depending on your needs. Just thought I'd mention it.
I don't want to speak for @rxi but I think the idea is that fe is so simple others can take it and mold it to their specific requirements. I've heavily customized fe for my use cases.
@rxi If you like the idea of officially adding an eval primitive to the interpreter, let me know. I'd be happy to prepare a pull request.