In Red/Rebol, parentheses () can be used to evaluate expressions like this:
>> (1 + 2 3 + 4)
== 7
However, when I use parentheses to evalute an anonymous function, it fails(please see the following code). Why? And how to make an anonymous function work?
>> (func [x y][x + y] 2 3)
== 3 ;;I think it should be 5.
PS:
>> do func [x y] [x + y]
== func [x y][x + y]
>> type? do func [x y] [x + y]
== function!
>> (do func [x y] [x + y]) 2 3
== 3 ;; why does this anonymous function still not work?
>> ((do func [x y] [x + y]) 2 3)
== 3 ;; This does not work too.
The reason is quite simple: there's no anonymous function in your code. It will become more evident if you scan its content as data:
That is to say:
func [x y][x + y]is aword!followed by 2block!s, not a function. Once evaluated though, it will yield back a function whose literal form will look exactly the same.funcis itself a function (aka function constructor) that creates another function.In your example
3is returned exactly for that reason: the interpreter evaluates each expression in sequence; the first expression is a function callfunc [x y][x + y]that takes two blocks and returns a function; the remaining expressions are literals2and3that evaluate to themselves; the result of the last expression is always returned in Red, so you get3. Parentheses in such case are superfluous.So, if you want to evaluate a function anonymously, you first need to create a
function!value from spec and body blocks with the help of function constructor (e.g.func,function,has,doesor some other one that you wrote yourself), and only then apply it to the arguments. The most common way to do so isdo reducepattern:reduceevaluates each sub-expression within a block (funccreates afunction!,2and3evaluate to themselves), anddothen interprets it (applies an anonymous function to two arguments).Here are some other approaches, so that you can get a grip of the concept:
As to why
do func [x y][x + y]works that way: this by design, to prevent variadic function calls. You can read a bit more on the rationale of it here.All functions in Rebol/Red have a fixed arity and evaluate only as many expressions as they need; function returning to the call-site and consuming the remaining arguments (like e.g. in Lisp) would go against this rule.
As a historical curiosity, Rebol3 had a
return/redorefinement which allowed functions to do just that, and which was later removed for the reasons I outlined above.Evaluation in the Rebol family is "layered", so to speak: values returned as results from functions don't get immediately re-evaluated if they are applicative, but rather need an extra pass from a top-level call to the evaluator (e.g.
doorreduce).