lambdaway
::
closure
7
|
list
|
login
|
load
|
|
{uncover http://lambdaway.free.fr/workshop/data/mies_pav.jpg 100 400 Less is more.} _h1 closure | [[unclosure]] | [[a workaround|?view=meta9]] _p Lambdatalk doesn't know [[closures| https://fr.wikipedia.org/wiki/Fermeture_(informatique)]]. But there is a life out of closures. See also [[stackoverflow|https://stackoverflow.com/questions/11590847/partial-application-and-closures]] _h2 1) IIFE can help _p The following code written in Lisp/Scheme (or [[lambdacode]]) {pre (define foo (lambda (a) (lambda (b) (* a b)))) ((foo 3) 4) // -> 12 } _p and this one written in Javascript {pre var foo = function(a) '{ return function(b) { return a*b } } foo(3)(4) // -> 12 } _p work fine, the value of {code a} is {i closed over} the inside lambda/function, but the similar one written in lambdatalk doesn't work {pre '{def foo {lambda {:a} {lambda {:b} {* :a :b}} }} -> {def foo {lambda {:a} {lambda {:b} {* :a :b}}}} '{{foo 3} 4} -> {{foo 3} 4} } _p because {code :a} is not in the internal lambda's list of arguments. In lambdatalk {b variables MUST be listed as arguments to be recognized!} _p A first workaround is to use an Immediately Invoked Function Expression, ({b IIFE}) {pre '{def bar {lambda {:a} {{lambda {:a :b} {* :a :b}} :a} // an IIFE partially applyed }} -> {def bar {lambda {:a} {{lambda {:a :b} {* :a :b}} :a}}} '{{bar 3} 4} -> {{bar 3} 4} } _p We have added the required {code :a} variable in a 2-adic lambda immediately invoqued on its value. The result is a 1-ary lambda whose body contains the value. _p Everything is OK! But a little bit tricky. Most of time we can do much simple. _h2 2) partial application is our friend _p Thanks to lambdas accepting {i de facto} partial applications we can simply write: {pre '{def baz {lambda {:a :b} // baz is waiting for two values {* :a :b} }} -> {def baz {lambda {:a :b} {* :a :b}}} } _p We can obviously apply this 2-adic function on two values {pre '{baz 3 4} -> {baz 3 4} } _p but we can apply it on two values given sequentially, first {pre '{baz 3} // baz is given only one value and returns -> {baz 3} // a lambda waiting for the missing value } _p and secondly {pre '{{baz 3} 4} // in fact '{_LAMB_10 4} -> {{baz 3} 4} } _p So, we have not to build a unary lambda returning another lambda but, we define a diary lambda which can be partially called and does the job under the cap. The result is the same, it's much more simple, it's easier to write and read. _p The [[fromroots2canopy]] page is full of useful applications to pairs, lists, recursion. _p But life is not always so easy. _h2 3) sometimes we need to carry the context _p Let's compute the area of a triangle/trigone {code [a=3,b=4,c=5]} using this formula {center {pre area = √{span {@ style="border-top:1px solid;"}s*(s-a)*(s-b)*(s-c)} where s=(a+b+c)/2 }} _p Using Lisp/Scheme we would write {pre (define area (lambda (a b c) ((lambda (s) (sqrt (* s (-s a) (- s b) (- s c))) ) (/ (+ a b c! 2) )) } _p where the internal lambda is applied on the computed {code s} variable, and the outer {code a,b,c} variables are automatically carryied in the internal lambda. _p But we know we can't do that in lambdatalk. We could code this formula this way {pre '{def area {lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }} } _p and call it with {code a=3, b=4, c=5, s = '{/ {+ 3 4 5} 2}} {pre '{area 3 4 5 {/ {+ 3 4 5} 2}} -> 6 } _p Bad way! The good way is to embed this 4-adic lambda in an IIFE which becomes the body of a 3-adic lambda {pre '{def area {lambda {:a :b :c} {{lambda {:a :b :c :s} // we MUST redefine outer variables {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} } :a :b :c // we MUST reassign outer values {/ {+ :a :b :c} 2}} // and add the new computed one }} -> {def area {lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}} :a :b :c {/ {+ :a :b :c} 2}}}} '{area 3 4 5} -> {area 3 4 5} } _h2 4) where {code let} makes things easier _p Lambdatalk comes with a {i syntactic sugar} for such a construction, the {code let} special form {center {pre '{{lambda {:vars} body} vals} <=> '{let { {:var_1 val_1} ...} body}}} _p which enlights the relation between variables and values {pre '{def area2 {lambda {:a :b :c} {let { {:a :a} // we MUST redefine the outer vars {:b :b} // and reassign the outer values {:c :c} // it's a kind of manual closure {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }}} -> {def area2 {lambda {:a :b :c} {let { {:a :a} {:b :b} {:c :c} {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }}} '{area2 3 4 5} -> {area2 3 4 5} } _h2 5) and so what? _p Well, some people find that too tricky, I admit it, and maybe in the future it will be possible to write {pre '{def area3 {lambda {:a :b :c} {let { // :a, :b, :c automatically redefined and reassigned {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}}}} } _p letting lambdatalk add {b automatically} the required variables and values, the {i lexical context}. Wait & see. _p {i Alain Marty | 2020/10/25} {style pre { box-shadow:0 0 8px #000; padding:10px; } }
lambdaway v.20211111