You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A grab expression computes a value inside a closure that depends on variables in the closure environment. It can also be used to precompute data at top level (more about this later).
Example:
fnmain(){
a := sift i 3{ \(x) = x + grab i }// Compute the value of `i` inside closurefor i {
println(\a[i](0))}}
A grab expression is evaluated when the closure is created and inserted into the AST of the closure variable. You can use any expression, as long as it returns a value:
grab i *5 + 2// OK
grab println("hi")// ERROR: Expected something, found `void`
It can not depend on any variable of the closure itself. Variables with same name will be reported as an error:
x := 2
a := \(x) = x + grab x // ERROR: Grabbed `x` has same name as closure variable
You can print out a closure to view the result of grab expression:
fnmain(){
a := \(x: f64) = x + grab prod i 3{ i + 1}println(a)// prints `\(x: f64) = x + 6`
println(\a(0))// prints `6`}
An error is shown if you try to use a grab expression outside a closure:
fnmain(){
a := grab 1 + 1println(a)}
--- ERROR ---
main (source/test.dyon)
`grab` expressions must be inside a closure
2,15: a := grab 2
2,15: ^
Grabbing higher levels
A closure inside a closure can contain a grab expression that computes values 1, 2 or higher levels:
a := \(x) = \(y) = \(z) = z + (grab y) + (grab '2 x)
Remember to use parenthesis (grab <expr>) if you are using multiple grab statements within same expression.
Thumb rule: The grab expression with highest level gets evaluated first.
Evaluation order
Blocks are evaluated after higher level expressions, such as in if expressions, where the conditions are evaluated before blocks:
fnmain(){
a := 5
b := \(x) = if x {grab{
println("two")
a
}} else if x < grab {println("one")
a - 2}{grab{
println("three")
a + 1}}// one// two// three// prints `\(x: any) = if x { 5 } else if x < 3 { 6 }`println(b)}
Otherwise, the evaluation follows top-down as you normally expect the code to be executed.
Precomputing data at top level
One can also use grab to precompute at top level. This is often used when the script is called frequently, e.g. to generate audio.
fnmain(){
a := grab [1,2,3]// Will be precomputed when loading script}
The following data can be precomputed:
Array fill, e.g. [false; 24]
Array, e.g. [1, 2, 3]
Object, e.g. {a: 1, b: 2}
4D vector, e.g. (1, 2, 3, 4)
Link structure, e.g. link {1 "hi" false}
The data structures can be nested, e.g. [[1, 2], [3, 4]] or [{a: 1, b: 3}, {a: 2, b: 4}].
Since the grab expression at top level injects the variable into the AST, when you mutate the variable Dyon will use copy-on-write. This means that grab expressions at top level is slower when mutating the variable, but faster when only reading from it.
Motivation
Adds a non-state capture ability of variables in the environment of closures. It is more powerful in the way that it works as a partial evaluation operator, but less flexible than mutable captured variables.
Dyon uses current objects for mutating the environment, so there is less need for capturing mutatable variables. A non-state capture is easier to reason about, requires no lifetime, and does not add overhead when calling closures.
The text was updated successfully, but these errors were encountered:
bvssvni
changed the title
Capture value of expressions in closures with capt keyword
Capture value of expressions in closures with grab keyword
Jun 24, 2016
bvssvni
changed the title
Capture value of expressions in closures with grab keywordgrab keyword
Jun 24, 2016
A
grab
expression computes a value inside a closure that depends on variables in the closure environment. It can also be used to precompute data at top level (more about this later).Example:
A
grab
expression is evaluated when the closure is created and inserted into the AST of the closure variable. You can use any expression, as long as it returns a value:It can not depend on any variable of the closure itself. Variables with same name will be reported as an error:
You can print out a closure to view the result of
grab
expression:An error is shown if you try to use a
grab
expression outside a closure:Grabbing higher levels
A closure inside a closure can contain a
grab
expression that computes values 1, 2 or higher levels:Remember to use parenthesis
(grab <expr>)
if you are using multiple grab statements within same expression.Thumb rule: The
grab
expression with highest level gets evaluated first.Evaluation order
Blocks are evaluated after higher level expressions, such as in
if
expressions, where the conditions are evaluated before blocks:Otherwise, the evaluation follows top-down as you normally expect the code to be executed.
Precomputing data at top level
One can also use
grab
to precompute at top level. This is often used when the script is called frequently, e.g. to generate audio.The following data can be precomputed:
[false; 24]
[1, 2, 3]
{a: 1, b: 2}
(1, 2, 3, 4)
link {1 "hi" false}
The data structures can be nested, e.g.
[[1, 2], [3, 4]]
or[{a: 1, b: 3}, {a: 2, b: 4}]
.Since the grab expression at top level injects the variable into the AST, when you mutate the variable Dyon will use copy-on-write. This means that grab expressions at top level is slower when mutating the variable, but faster when only reading from it.
Motivation
Adds a non-state capture ability of variables in the environment of closures. It is more powerful in the way that it works as a partial evaluation operator, but less flexible than mutable captured variables.
Dyon uses current objects for mutating the environment, so there is less need for capturing mutatable variables. A non-state capture is easier to reason about, requires no lifetime, and does not add overhead when calling closures.
The text was updated successfully, but these errors were encountered: