Runtime evaluation/In an environment: Difference between revisions
m Fixed lang tags. |
|||
Line 20: | Line 20: | ||
<!-- {{does not work with|ELLA ALGOL 68|Any This implementation is a compiler}} --> |
<!-- {{does not work with|ELLA ALGOL 68|Any This implementation is a compiler}} --> |
||
Variable names are generally not visible at run time with classic compilers. However '''ALGOL 68G''' is an interpretor and it retains this ability. Note that ''evaluate'' returns a '''string'''. |
Variable names are generally not visible at run time with classic compilers. However '''ALGOL 68G''' is an interpretor and it retains this ability. Note that ''evaluate'' returns a '''string'''. |
||
<lang |
<lang algol68>PROC eval_with_x = (STRING code, INT a, b)STRING: |
||
(INT x=a; evaluate(code) ) + (INT x=b; evaluate(code)); |
(INT x=a; evaluate(code) ) + (INT x=b; evaluate(code)); |
||
print((eval_with_x("2 ** x", 3, 5), new line))</lang> |
print((eval_with_x("2 ** x", 3, 5), new line))</lang> |
||
Line 29: | Line 29: | ||
=={{header|Common Lisp}}== |
=={{header|Common Lisp}}== |
||
<lang lisp> |
<lang lisp>(defun eval-with-x (program a b) |
||
(defun eval-with-x (program a b) |
|||
(let ((at-a (eval `(let ((x ',a)) ,program))) |
(let ((at-a (eval `(let ((x ',a)) ,program))) |
||
(at-b (eval `(let ((x ',b)) ,program)))) |
(at-b (eval `(let ((x ',b)) ,program)))) |
||
(- at-b at-a))) |
(- at-b at-a)))</lang> |
||
⚫ | |||
<lang lisp> |
<lang lisp>(eval-with-x '(exp x) 0 1) |
||
⚫ | |||
(eval-with-x '(exp x) 0 1) |
|||
⚫ | |||
</lang> |
|||
This version ensures that the program is compiled, once, for more efficient execution: |
This version ensures that the program is compiled, once, for more efficient execution: |
||
<lang lisp> |
<lang lisp>(defun eval-with-x (program a b) |
||
(defun eval-with-x (program a b) |
|||
(let* ((f (compile nil `(lambda (x) ,program))) |
(let* ((f (compile nil `(lambda (x) ,program))) |
||
(at-a (funcall f a)) |
(at-a (funcall f a)) |
||
(at-b (funcall f b))) |
(at-b (funcall f b))) |
||
(- at-b at-a))) |
(- at-b at-a)))</lang> |
||
</lang> |
|||
=={{header|E}}== |
=={{header|E}}== |
||
Line 72: | Line 66: | ||
=={{header|Forth}}== |
=={{header|Forth}}== |
||
EVALUATE invokes the Forth interpreter on the given string. |
EVALUATE invokes the Forth interpreter on the given string. |
||
<lang forth> |
<lang forth>: f-" ( a b snippet" -- ) |
||
: f-" ( a b snippet" -- ) |
|||
[char] " parse ( code len ) |
[char] " parse ( code len ) |
||
2dup 2>r evaluate |
2dup 2>r evaluate |
||
Line 79: | Line 72: | ||
- . ; |
- . ; |
||
2 3 f-" dup *" \ 5 (3*3 - 2*2) |
2 3 f-" dup *" \ 5 (3*3 - 2*2)</lang> |
||
</lang> |
|||
This can be used to treat a data stream as code, or to provide a lightweight macro facility when used in an IMMEDIATE word. |
This can be used to treat a data stream as code, or to provide a lightweight macro facility when used in an IMMEDIATE word. |
||
<lang forth> |
<lang forth>: :macro ( "name <char> ccc<char>" -- ) |
||
: :macro ( "name <char> ccc<char>" -- ) |
|||
: [CHAR] ; PARSE POSTPONE SLITERAL POSTPONE EVALUATE |
: [CHAR] ; PARSE POSTPONE SLITERAL POSTPONE EVALUATE |
||
POSTPONE ; IMMEDIATE |
POSTPONE ; IMMEDIATE |
||
Line 97: | Line 88: | ||
DO .\" spam " |
DO .\" spam " |
||
LOOP |
LOOP |
||
; ok |
; ok</lang> |
||
</lang> |
|||
=={{header|Genyris}}== |
=={{header|Genyris}}== |
||
One way is to use a macro. In genyris, macros are lazy functions which execute twice, the return value is also evaluated in the caller's environment: |
One way is to use a macro. In genyris, macros are lazy functions which execute twice, the return value is also evaluated in the caller's environment: |
||
⚫ | |||
<lang python> |
|||
⚫ | |||
var x 23 |
var x 23 |
||
Line 115: | Line 104: | ||
Another way is to use dynamically scoped variables. In Genyris, symbols prefixed with a period are looked up in the caller's environment, not the lexical environment of the closure. When a dictionary is the first element of the expression, an environment is created and the &rest is evaluated. |
Another way is to use dynamically scoped variables. In Genyris, symbols prefixed with a period are looked up in the caller's environment, not the lexical environment of the closure. When a dictionary is the first element of the expression, an environment is created and the &rest is evaluated. |
||
<lang |
<lang genyris>def add100() (+ .x 100) |
||
(dict) # create an environment capable of holding dynamic bindings |
(dict) # create an environment capable of holding dynamic bindings |
||
Line 124: | Line 113: | ||
+ firstresult (add100)</lang> |
+ firstresult (add100)</lang> |
||
Dictionaries can hold bindings to dynamic symbols. To minimize the danger of dynamic scope there is no recursive ascent in the binding lookup. |
Dictionaries can hold bindings to dynamic symbols. To minimize the danger of dynamic scope there is no recursive ascent in the binding lookup. |
||
⚫ | |||
<lang python> |
|||
⚫ | |||
var .x 23 |
var .x 23 |
||
(dict) |
(dict) |
||
Line 150: | Line 138: | ||
===Explicit=== |
===Explicit=== |
||
The following satisfies the requirements: |
The following satisfies the requirements: |
||
<lang j> |
<lang j> EvalWithX=. monad : 0 |
||
EvalWithX=. monad : 0 |
|||
'CODE V0 V1'=. y |
'CODE V0 V1'=. y |
||
(". CODE [ x=. V1) - (". CODE [ x=. V0) |
(". CODE [ x=. V1) - (". CODE [ x=. V0) |
||
Line 157: | Line 144: | ||
EvalWithX '^x';0;1 |
EvalWithX '^x';0;1 |
||
1.71828183 |
1.71828183</lang> |
||
</lang> |
|||
===Tacit=== |
===Tacit=== |
||
However, it is easier via point-free coding: |
However, it is easier via point-free coding: |
||
⚫ | |||
<lang j> |
|||
⚫ | |||
⚫ | |||
1.71828183 |
|||
</lang> |
|||
=={{header|JavaScript}}== |
=={{header|JavaScript}}== |
||
Line 312: | Line 296: | ||
=={{header|TI-89 BASIC}}== |
=={{header|TI-89 BASIC}}== |
||
<lang ti89b>evalx(prog, a, b) |
|||
Func |
|||
Local x,eresult1,eresult2 |
|||
a→x |
|||
expr(prog)→eresult1 |
|||
b→x |
|||
expr(prog)→eresult2 |
|||
Return eresult2-eresult1 |
|||
EndFunc |
|||
■ evalx("ℯ^x", 0., 1) |
|||
1.71828</lang> |
|||
There are no facilities for control over the environment; expr() evaluates in the same environment as the caller, including local variables. [Someone please verify this statement.] [[Category:TI-89 BASIC examples needing attention]] |
There are no facilities for control over the environment; expr() evaluates in the same environment as the caller, including local variables. [Someone please verify this statement.] [[Category:TI-89 BASIC examples needing attention]] |
Revision as of 01:48, 20 November 2009
You are encouraged to solve this task according to the task description, using any language you may know.
Given a program in the language (as a string or AST) with a free variable named x (or another name if that is not valid syntax), evaluate it with x bound to a provided value, then evaluate it again with x bound to another provided value, then subtract the result of the first from the second and return or print it.
Do so in a way which:
- does not involve string manipulation of the input source code
- is plausibly extensible to a runtime-chosen set of bindings rather than just x
- does not make x a global variable
or note that these are impossible.
See also
- For more general examples and language-specific details, see Eval.
- Dynamic variable names is a similar task.
ALGOL 68
Variable names are generally not visible at run time with classic compilers. However ALGOL 68G is an interpretor and it retains this ability. Note that evaluate returns a string. <lang algol68>PROC eval_with_x = (STRING code, INT a, b)STRING: (INT x=a; evaluate(code) ) + (INT x=b; evaluate(code)); print((eval_with_x("2 ** x", 3, 5), new line))</lang> Output:
+8 +32
Common Lisp
<lang lisp>(defun eval-with-x (program a b)
(let ((at-a (eval `(let ((x ',a)) ,program))) (at-b (eval `(let ((x ',b)) ,program)))) (- at-b at-a)))</lang>
<lang lisp>(eval-with-x '(exp x) 0 1) => 1.7182817</lang>
This version ensures that the program is compiled, once, for more efficient execution:
<lang lisp>(defun eval-with-x (program a b)
(let* ((f (compile nil `(lambda (x) ,program))) (at-a (funcall f a)) (at-b (funcall f b))) (- at-b at-a)))</lang>
E
<lang e># Constructing an environment has to be done by way of evaluation for historical reasons which will hopefully be entirely eliminated soon. def bindX(value) {
def [resolver, env] := e` def x # bind x and capture its resolver and the resulting environment `.evalToPair(safeScope) resolver.resolve(value) # set the value return env
}
def evalWithX(program, a, b) {
def atA := program.eval(bindX(a)) def atB := program.eval(bindX(b)) return atB - atA
}</lang>
<lang e>? evalWithX(e`(x :float64).exp()`, 0, 1)
- value: 1.7182818284590455</lang>
Forth
EVALUATE invokes the Forth interpreter on the given string. <lang forth>: f-" ( a b snippet" -- )
[char] " parse ( code len ) 2dup 2>r evaluate swap 2r> evaluate - . ;
2 3 f-" dup *" \ 5 (3*3 - 2*2)</lang> This can be used to treat a data stream as code, or to provide a lightweight macro facility when used in an IMMEDIATE word. <lang forth>: :macro ( "name <char> ccc<char>" -- )
: [CHAR] ; PARSE POSTPONE SLITERAL POSTPONE EVALUATE POSTPONE ; IMMEDIATE
- macro times 0 do ;
- test 8 times ." spam " loop ;
see test
- test
8 0 DO .\" spam " LOOP ; ok</lang>
Genyris
One way is to use a macro. In genyris, macros are lazy functions which execute twice, the return value is also evaluated in the caller's environment: <lang genyris>defmacro add100() (+ x 100)
var x 23 var firstresult (add100) x = 1000 print
+ firstresult (add100)</lang>
This prints 1223.
Another way is to use dynamically scoped variables. In Genyris, symbols prefixed with a period are looked up in the caller's environment, not the lexical environment of the closure. When a dictionary is the first element of the expression, an environment is created and the &rest is evaluated.
<lang genyris>def add100() (+ .x 100)
(dict) # create an environment capable of holding dynamic bindings
var .x 23 # create a binding in the dictionary var firstresult (add100) .x = 1000 print + firstresult (add100)</lang>
Dictionaries can hold bindings to dynamic symbols. To minimize the danger of dynamic scope there is no recursive ascent in the binding lookup. <lang genyris>(dict)
var .x 23 (dict) print .x # fails</lang>
Groovy
The solution: <lang groovy>def cruncher = { x1, x2, program ->
Eval.x(x1, program) - Eval.x(x2, program)
}</lang>
Test Program: <lang groovy>def fibonacciProgram = x < 1 ? 0 : x == 1 ? 1 : (2..x).inject([0,1]){i, j -> [i[1], i[0]+i[1]]}[1]
println "F(${10}) - F(${5}) = ${Eval.x(10, fibonacciProgram)} - ${Eval.x(5, fibonacciProgram)} = " + cruncher(10, 5, fibonacciProgram)</lang>
Output:
F(10) - F(5) = 55 - 5 = 50
J
Explicit
The following satisfies the requirements: <lang j> EvalWithX=. monad : 0
'CODE V0 V1'=. y (". CODE [ x=. V1) - (". CODE [ x=. V0) ) EvalWithX '^x';0;1
1.71828183</lang>
Tacit
However, it is easier via point-free coding: <lang j> (0&({::) -~&>/@:(128!:2&.>) 1 2&{) '^';0;1 1.71828183</lang>
JavaScript
eval uses the environment from the calling function.
<lang javascript>function evalWithX(expr, a, b) {
var x = a; var atA = eval(expr); x = b; var atB = eval(expr); return atB - atA;
}</lang>
<lang javascript>evalWithX('Math.exp(x)', 0, 1) // returns 1.718281828459045</lang>
Metafont
<lang metafont>vardef evalit(expr s, va, vb) = save x,a,b; x := va; a := scantokens s; x := vb; b := scantokens s; a-b enddef;
show(evalit("2x+1", 5, 3)); end</lang>
Octave
In Octave, undeclared variables are local.
<lang octave>function r = calcit(f, val1, val2)
x = val1; a = eval(f); x = val2; b = eval(f); r = b-a;
endfunction
p = "x .* 2"; disp(calcit(p, [1:3], [4:6]));</lang>
Output:
6 6 6
Perl
<lang perl>sub eval_with_x
{my $code = shift; my $x = shift; my $first = eval $code; $x = shift; return eval($code) - $first;}
print eval_with_x('3 * $x', 5, 10), "\n"; # Prints "15".</lang>
PHP
<lang php><?php function eval_with_x($code, $a, $b) {
$x = $a; $first = eval($code); $x = $b; $second = eval($code); return $second - $first;
}
echo eval_with_x('return 3 * $x;', 5, 10), "\n"; # Prints "15". ?></lang>
Python
<lang python>>>> def eval_with_x(code, a, b): return eval(code, {'x':b}) - eval(code, {'x':a})
>>> eval_with_x('2 ** x', 3, 5) 24</lang>
A slight change allows the evaluation to take multiple names: <lang python>>>> def eval_with_args(code, **kwordargs): return eval(code, kwordargs)
>>> code = '2 ** x' >>> eval_with_args(code, x=5) - eval_with_args(code, x=3) 24 >>> code = '3 * x + y' >>> eval_with_args(code, x=5, y=2) - eval_with_args(code, x=3, y=1) 7</lang>
R
We can set up thing so that the "unbound" variable can be any accepted symbol for variables. <lang R>evalWithAB <- function(expr, var, a, b) {
env <- new.env() # provide a separate env, so that the choosen assign(var, a, envir=env) # var name do not collide with symbols inside # this function (e.g. it could be even "env") atA <- eval(parse(text=expr), env) # and then evaluate the expression inside this # ad hoc env-ironment assign(var, b, envir=env) atB <- eval(parse(text=expr), env) return(atB - atA)
}
print(evalWithAB("2*x+1", "x", 5, 3)) print(evalWithAB("2*y+1", "y", 5, 3)) print(evalWithAB("2*y+1", "x", 5, 3)) # error: object "y" not found</lang>
Ruby
<lang ruby>def bind_x_to_value(x)
binding
end
def eval_with_x(code, a, b)
eval(code, bind_x_to_value(b)) - eval(code, bind_x_to_value(a))
end
puts eval_with_x('2 ** x', 3, 5) # Prints "24"</lang>
The magic here is how the binding
method works with the bind_x_to_value(x)
method.
When bind_x_to_value
is called, it sets its local variable x
to the value passed.
The binding
method then returns a reference to the current context (or stack frame) to the caller.
eval
can then use the local variable x
in this context.
Scheme
Almost identical to the Common Lisp version above. <lang scheme>(define (eval-with-x prog a b)
(let ((at-a (eval `(let ((x ',a)) ,prog))) (at-b (eval `(let ((x ',b)) ,prog)))) (- at-b at-a)))</lang>
Tcl
<lang tcl>proc eval_twice {func a b} {
set x $a set 1st [expr $func] set x $b set 2nd [expr $func] expr {$2nd - $1st}
}
puts [eval_twice {2 ** $x} 3 5] ;# ==> 24</lang>
Here's another take, similar to other answers. It passes a code block to be eval
ed, not just an expression for expr
<lang tcl>proc eval_with_x {code val1 val2} {
expr {[set x $val2; eval $code] - [set x $val1; eval $code]}
} eval_with_x {expr {2**$x}} 3 5 ;# ==> 24</lang>
TI-89 BASIC
<lang ti89b>evalx(prog, a, b) Func
Local x,eresult1,eresult2 a→x expr(prog)→eresult1 b→x expr(prog)→eresult2 Return eresult2-eresult1
EndFunc
■ evalx("ℯ^x", 0., 1)
1.71828</lang>
There are no facilities for control over the environment; expr() evaluates in the same environment as the caller, including local variables. [Someone please verify this statement.]