Closures/Value capture: Difference between revisions

m
(added Arturo)
 
(8 intermediate revisions by 5 users not shown)
Line 26:
9
</pre>
 
=={{header|Acornsoft Lisp}}==
 
Since this Lisp is dynamically scoped and does not have any built-in closure mechanism, we have to construct one which we'll call <code>freeze</code>. (The name is inspired by the [[Pop-2]] programming languages's "frozen formals".)
 
('''freeze''' ''varlist lambda-expr'') finds the current values of the variables in ''varlist'' and returns a lambda-expression that is like the original except that, when called, it binds those variables to their captured values. For example, if <code>a</code>'s value is 1 and <code>b</code>'s is 2,
 
<syntaxhighlight lang="lisp">
(freeze '(a b) '(lambda (c) (list a b c)))
</syntaxhighlight>
 
would return
 
<syntaxhighlight lang="lisp">
(lambda (c)
((lambda ((a . 1) (b . 2))
(list a b c))))
</syntaxhighlight>
 
What does that mean? A cons (''name'' . ''value'') in a lambda-expressions's formal parameters is the syntax for a formal with a default value. The ''value'' is literally the value; it's not an expression that's evaluated. This
 
<syntaxhighlight lang="lisp">
( (lambda ((a . 1) (b . 2))
(list a b c)) )
</syntaxhighlight>
 
calls the function represented by that lambda-expression. Since it does not give the function any arguments, <code>a</code> and <code>b</code> get their default values (which are the values captured by <code>freeze</code>).
 
(Although code within such a 'closure' can assign new values to the captured variables, it would have only a temporary effect and would not change the values seen in subsequent calls to the same closure. That's one sense in which the variable values are "frozen".)
 
Here is the definition of <code>freeze</code>:
 
<syntaxhighlight lang="lisp">
(defun freeze (_fvars_ _lambda-expr_)
(freeze-vars
(mapc cons _fvars_ (mapc eval _fvars_))
(cadr _lambda-expr_)
(cddr _lambda-expr_)))
 
(defun freeze-vars (bindings lvars lbody)
(list 'lambda lvars
(list (cons 'lambda (cons bindings lbody)))))
</syntaxhighlight>
 
Once we have <code>freeze</code>, we can create a list of square-returning functions and then call them:
 
<syntaxhighlight lang="lisp">
(defun range (from to)
(cond ((greaterp from to) '())
(t (cons from (range (add1 from) to)))))
 
(defun example ()
(mapc '(lambda (f) (f))
(mapc '(lambda (i)
(freeze '(i) '(lambda () (times i i))))
(range 1 10))))
</syntaxhighlight>
 
{{Out}}
 
<code>(example)</code> returns
<pre>(1 4 9 16 25 36 49 64 81 100)</pre>
 
=={{header|Ada}}==
 
Line 586 ⟶ 649:
</syntaxhighlight>
=={{header|Elena}}==
ELENA 46.1x :
<syntaxhighlight lang="elena">import system'routines;
import extensions;
Line 592 ⟶ 655:
public program()
{
var functions := Array.allocate(10).populate::(int i => { ^ i * i} );
functions.forEach::(func) { console.printLine(func()) }
}</syntaxhighlight>
{{out}}
Line 607 ⟶ 670:
64
81</pre>
 
=={{header|Elixir}}==
<syntaxhighlight lang="elixir">funs = for i <- 0..9, do: (fn -> i*i end)
Line 917 ⟶ 981:
{{out}}
<pre>Randomly selecting L[8] = 64</pre>
 
=={{Header|Insitux}}==
 
<syntaxhighlight lang="insitux">
(var funcs (for x (range 11) #(* x x)))
 
[(0 funcs) ((3 funcs)) ((4 funcs))]
</syntaxhighlight>
 
{{out}}
 
<pre>
[#(* x x) 9 16]
</pre>
 
=={{header|Io}}==
<syntaxhighlight lang="text">blist := list(0,1,2,3,4,5,6,7,8,9) map(i,block(i,block(i*i)) call(i))
Line 955 ⟶ 1,034:
slist@.(?9) ''
25</syntaxhighlight>
 
===Using temporary locales===
The problem statement "Demonstrate how to create a series of independent closures based on the same template but maintain separate copies of the variable closed over" conflicts with the problem title "Value capture" in languages have sufficient abstraction to distinguish between value capture and variable and variable capture. This conflict even appears in J, and in general cases can require treatment of issues well outside the scope of this task.
 
Still, to address the task description, we should include a "variable capture" implementation, which in J could imply the use of "temporary [[j:Vocabulary/Locales#Summary_of_the_Locale_Mechanism|locales]]" despite the fact that this approach would not satisfy the "simplest fashion possible" requirement.
 
For example, we could define an adverb 'geni' which takes a base function (which in this case will be <code>*:</code> -- a function which squares an argument) and a value (which in this case will be an index), creates a locale where that value will be stored in a variable named <code>i</code> and then returns an anonymous function which takes a reference to the locale (rather than the value) and extracts the value from the locale to generate the result.
 
We'll also use J's nuvoc <code><nowiki>{{</nowiki></code> ... <code><nowiki>}}</nowiki></code> nesting definitional mechanism which implicitly determines the type of a definition instead of explicitly representing the definition types (<code>1 :</code>, <code>2 :</code>, <code>3 :</code>, ...) which discourages nesting blocks.
 
<syntaxhighlight lang=J>
geni=: {{
N=. cocreate''
i__N=. y
N
}}
task=: {{ u {{ u {{ u i__n [ y }} (geni y)`'' }}"0 i. y }}
</syntaxhighlight>
 
This would be really bad form if we were intending to be useful, but - as described above - this approach is somewhat relevant to the task requirements.
 
Example use:
<syntaxhighlight lang=J>
fns=: *: task 10
fns@.3 ''
9
fns@.5 ''
25
fns@.7 ''
49
</syntaxhighlight>
 
 
===Tacit (unorthodox) version===
In J only adverbs and conjunctions (functionals) can produce verbs (functions)... Unless they are forced to cloak as verbs; in this instance, the rank conjunction (“) cloaks as a dyadic verb. (NoteThis thatdoes not work in recent versions of J as this takes advantage of a bug/feature where the interpreter does not produce a result with [http://www.jsoftware.com/help/dictionary/dictb.htm the correct shape]):
 
<syntaxhighlight lang="j"> ( VL=. (<@:((<'"')(0:`)(,^:)&_))"0@:(^&2)@:i. 10 ) NB. Producing a list of boxed anonymous verbs (functions)
Line 968 ⟶ 1,079:
{::&VL 5 '' NB. Invoking the 6th verb with a dummy argument ('')
25</syntaxhighlight>
 
=={{header|Java}}==
{{works with|Java|8+}}
Line 2,189 ⟶ 2,301:
Whenever we call a continuation, the <code>(block sqr ...)</code> environment is restored. and the suspended computation inside the block resumes by returning out of the <code>(suspend ...)</code> form normally. The block then executes to completion, returning the <code>(* cap cap)</code> form's value. At that point, our call to the continuation terminates, yielding that value.
=={{header|Wren}}==
<syntaxhighlight lang="ecmascriptwren">var fs = List.filled(10, null)
for (i in 0...fs.count) {
fs[i] = Fn.new { i * i }
Line 2,208 ⟶ 2,320:
Function #8: 64
</pre>
 
=={{header|Yabasic}}==
<syntaxhighlight lang="Yabasic">
6,951

edits