Runtime evaluation/In an environment: Difference between revisions

From Rosetta Code
Content added Content deleted
m (→‎{{header|REXX}}: removed optionds to pre box)
Line 215: Line 215:


Of course this could be re-defined such that the free variable declaration appears to the left of the expression (<code>'Z' 'Z + 2^Z' Example 2 3</code>). However, J's currying and precedence rules might make that less convenient to use, if this were ever used in a real program.
Of course this could be re-defined such that the free variable declaration appears to the left of the expression (<code>'Z' 'Z + 2^Z' Example 2 3</code>). However, J's currying and precedence rules might make that less convenient to use, if this were ever used in a real program.
=={{header|Java}}==
Java is compiled static language and expression evaluation is not intrinsic part of Java or the standard libraries. In scripting languages for example - it makes sense to have eval method, as interpreter can interpret string and include it's contents as part of the surrounding methods, with complete access to local variables.

Clearly there are lots of ways to get around the problem, but as of Java 6, Java can contain scripting environments. For example Mozilla Rihno JavaScript engine is contained in JDK 6 Bean Scripting Framework.

Example:
<lang Java>
ScriptEngine js = new ScriptEngineManager().getEngineByName("js");
System.out.println(js.eval("function D(x){return x*2;} var x=3; x=D(x);"));
</lang>

Output:
<pre>6.0</pre>


=={{header|JavaScript}}==
=={{header|JavaScript}}==

Revision as of 13:52, 19 March 2011

Task
Runtime evaluation/In an environment
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

ALGOL 68

Works with: ALGOL 68G version Any - tested with release mk15-0.8b.fc9.i386 - this implementation is an interpretor, and evaluate is an extension to the standard

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

AutoHotkey

Works with: AutoHotkey_H

AutoHotkey does not provide an API to the local symbol table. Local variables are also not supported within scopes outside functions. However, a local environment can be simulated by wrapping code in a temporary function. <lang AutoHotkey>msgbox % first := evalWithX("x + 4", 5) msgbox % second := evalWithX("x + 4", 6) msgbox % second - first return

evalWithX(expression, xvalue) { global script script = (

   expression(){
   x = %xvalue%  ; := would need quotes
   return %expression%
 }

) renameFunction("expression", "")  ; remove any previous expressions gosub load ; cannot use addScript inside a function yet exp := "expression" return %exp%() }

load: DllCall(A_AhkPath "\addScript","Str",script,"Uchar",0,"Cdecl UInt") return

renameFunction(funcName, newname){ static x%newname% := newname  ; store newname in a static variable so its memory is not freed strput(newname, &x%newname%, strlen(newname) + 1) if fnp := FindFunc(funcName)

 numput(&x%newname%, fnp+0, 0, "uint")

}</lang>

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

Some lines in this example are too long (more than 80 characters). Please fix the code if it's possible and remove this message.

<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)

  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>

Explicit again

Or, using y as the free variable, instead of x: <lang J>EvalDiffWithY=: dyad define

  -~/verb def x"_1 y

)</lang>

Example use:

<lang J> '^y' EvalDiffWithY 0 1 1.71828</lang>

This can be extended to support a user declared argument name:

<lang J>EvalDiffWithName=: adverb define

  -~/m adverb def ('(m)=.y';x)"_1 y

)</lang>

This works by preceding the user provided expression with a statement which assigns the argument value to a local variable whose name was provided by the user. [Note that this implementation skirts the requirement that the implementation does not manipulate strings -- instead we manipulate a structure containing strings.]

Example use:

<lang J> '^George' 'George' EvalDiffWithName 0 1 1.71828

  'Z + 2^Z' 'Z' EvalDiffWithName 2 3

5</lang>

Of course this could be re-defined such that the free variable declaration appears to the left of the expression ('Z' 'Z + 2^Z' Example 2 3). However, J's currying and precedence rules might make that less convenient to use, if this were ever used in a real program.

Java

Java is compiled static language and expression evaluation is not intrinsic part of Java or the standard libraries. In scripting languages for example - it makes sense to have eval method, as interpreter can interpret string and include it's contents as part of the surrounding methods, with complete access to local variables.

Clearly there are lots of ways to get around the problem, but as of Java 6, Java can contain scripting environments. For example Mozilla Rihno JavaScript engine is contained in JDK 6 Bean Scripting Framework.

Example:

<lang Java> ScriptEngine js = new ScriptEngineManager().getEngineByName("js"); System.out.println(js.eval("function D(x){return x*2;} var x=3; x=D(x);")); </lang>

Output:

6.0

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>


Lua

<lang lua> code = loadstring"return x^2" --this doesn't really need to be input, does it? val1 = setfenv(code, {x = io.read() + 0})() val2 = setfenv(code, {x = io.read() + 0})() print(val2 - val1) </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

Oz

<lang oz>declare

  fun {EvalWithX Program A B}
     {Compiler.evalExpression Program env('X':B) _}
     -
     {Compiler.evalExpression Program env('X':A) _}   
  end

in

  {Show {EvalWithX "{Exp X}" 0.0 1.0}}</lang>

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>

PicoLisp

<lang PicoLisp>(let Expression '(+ X (* X X)) # Local expression

  (println
     (+
        (let X 3
           (eval Expression) )
        (let X 4
           (eval Expression) ) ) )
  (let Function (list '(X) Expression)   # Build a local function
     (println
        (+
           (Function 3)
           (Function 4) ) ) ) )</lang>

Output:

32
32

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>

REBOL

<lang rebol>prog: [x * 2] fn: func [x] [do bind prog 'x] a: fn 2 b: fn 4 subtract b a</lang>

Result:

4

REXX

<lang rexx> a=x(3) b=x(4) say b-a exit


x: procedure;arg n;!=1;do j=2 to n;!=!*j;end;return ! </lang> Output:

18

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 evaled, 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.]