lambdaspeech
::
closure
2
|
list
|
login
|
load
|
|
_h1 closure | [[variadic]] | [[let]] _p The concept of {b closure} in computing is not so easy to understand. You might have a look at [[https://en.m.wikipedia.org/wiki/Talk:Closure_(computer_science)|https://en.m.wikipedia.org/wiki/Talk:Closure_(computer_science)]] to be convinced. I just keep this definition "{i The core notion of a closure is an implementation concept rather than a language feature.} " and this other one " {i The reason it is called a "closure" is that an expression containing free variables is called an "open" expression, and by associating to it the bindings of its free variables, you close it. —Ake Wikstrom, Functional Programming using Standard ML} " _p Via the {i original/non standard} implementation of '{lambda talk} I discovered that {b closure} is not mandatory in functional programming provided functions accept {b partial application}. For instance in Scheme we should write the {b [cons,car,cdr]} structure using a closure {pre (def cons (lambda (x y) (lambda (z) (z x y)))) (def car (lambda (z) (z (lambda (x y) x)))) (def cdr (lambda (z) (z (lambda (x y) y)))) (car (cons '♥ '♠)) -> ♥ (cdr (cons '♥ '♠)) -> ♠ } _p The {b cons} function waits for 2 values and returns a function waiting for 1 function to be applied to the 2 values kept in a closure created by the {b cons} function. _p Contrary to Scheme '{lambda talk} doesn't know closures, a lambda can't have free variables getting their values from the outer context, {u all variables must be defined in the list of arguments}. A lambda is progressively invoked on values and stores them in its body {pre '{{lambda {x y} x y} ♥ ♠} -> '{{lambda {y} ♥ y} ♠} -> '{{lambda {} ♥ ♠}} -> ♥ ♠ } _p And so we can use partial application to build the [cons,car,cdr] structure {pre °° {def cons {lambda {x y z} {z x y}}} {def car {lambda {z} {z {lambda {x y} x}}}} {def cdr {lambda {z} {z {lambda {x y} y}}}} {car {cons ♥ ♠}} -> ♥ {cdr {cons ♥ ♠}} -> ♠ °°} _p The {b cons} function waits for 3 values but will be feeded with only 2. The result will be a function memorizing the given values in its body - a string - and waiting for the missing one. Let's trace the {b car} application to a pair, just replacing lambda's refs by their lambda expressions {pre °° . {{lambda {z} {z {lambda {x y} x}}} {{lambda {x y z} {z x y}} ♥ ♠}} == ♥ -> {{lambda {z} {z {lambda {x y} x}}} {{lambda {y z} {z ♥ y}} ♠}} == ♥ -> {{lambda {z} {z {lambda {x y} x}}} {{lambda {z} {z ♥ ♠}}}} == ♥ -> {{lambda {z} {z {lambda {x y} x}}} {lambda {z} {z ♥ ♠}} } == ♥ -> {{lambda {z} {z ♥ ♠}} {lambda {x y} x}} == ♥ -> {{lambda {x y} x} ♥ ♠} == ♥ -> ♥ °°} _p It's just text substitutions. _ul Another useful property of lambdas in '{lambda talk} is that they accept a number of values greater than the number of arguments. Extra arguments are simply gathrered in the last one. A kind of variadicity. _ul Note that in Scheme words must be quoted and not in '{lambda talk}. _p See also [[let]], [[variadic]]. _p See also _ul [[are-closures-considered-impure-functional-style|https://softwareengineering.stackexchange.com/questions/235175/are-closures-considered-impure-functional-style]] _ul [[https://www.jamesporter.me/2013/06/14/emacs-lisp-closures-exposed.html|https://www.jamesporter.me/2013/06/14/emacs-lisp-closures-exposed.html]] _p The last link speaks about emacs-lisp and workarounds to the lack of closure. Let's see: {pre 1) javascript var fun1 = function() '{ var x = 12; return function (y) { return x*y; }; }; fun1()(3) // -> 36 2) emacs-lisp: (funcall (let ((x 12)) (lambda (y) (* x y))) 3) -> error (setq lexical-binding t) (let ((x 12)) (lambda (y) (* x y))) -> (closure ((x . 12) t) (y) (* x y)) (funcall (closure ((x . 12) t) (y) (* x y)) 3) -> 36 3) lambdatalk: '{def fun1 {lambda {y} {let {{x 12} {y y}} // manual closure, y must be redefined {* x y}}}} // x gets 12 from closure, y from function call -> {def fun1 {lambda {y} {let {{x 12} {y y}} {* x y}}}} which is a syntactic sugar for an IIFE '{def fun2 {lambda {y} {{lambda {x y} {* x y}} 12 y}}} -> {def fun2 {lambda {y} {{lambda {x y} {* x y}} 12 y}}} '{fun1 3} -> {fun1 3} '{fun2 3} -> {fun2 3} }
lambdaspeech v.20200126