lambdaspeech
::
let
1
|
list
|
login
|
load
|
|
_h1 let | [[variadic]] | [[closure]] _p Immediatly Invoked Function Expression, (IIFE), {code '{{lambda {args} body} vals}} are frequently used in functional programming. The {code '{let { {arg val} ...} body}} expression is a useful syntaxic sugar enlighting local variables. _p This is probably the simplest introduction {pre '{let { // 1) define local vars and functions {:x 3} // x = 3 {:y 4} // y = 4 {:sqr {lambda {:x} {* :x :x}}} // sqr = function(x) { return x*x } } {sqrt {+ {:sqr :x} {:sqr :y}}} // 2) and compute } -> {let { {:x 3} {:y 4} {:sqr {lambda {:x} {* :x :x}}} } {sqrt {+ {:sqr :x} {:sqr :y}}} } } _p Looks like this Javascript code {pre var x = 3, y = 4, sqr = function (x) '{ return x*x } return Math.sqrt(sqr(x) + sqr(y)); } _h2 1. from an IIFE to let _p In such an expression {code (1+x){sup 3}+(1+x){sup 2}+(1+x)} {code 1+x} is computed three times. It's efficient to replace {code 1+x} by some local variable {code u}, compute its value once and then {code u{sup 3}+u{sup 2}+u}. The first approach is to use an IIFE {pre '{def foo {lambda {:x} {{lambda {:u} {+ {pow :u 3} {pow :u 2} :u} } {+ 1 :x}} }} -> {def foo {lambda {:x} {{lambda {:u} {+ {pow :u 3} {pow :u 2} :u} } {+ 1 :x}} }} '{foo 4} -> {foo 4} } _p A better approach is to use the let special form, which enlights the relation between the local variable {code :u} and its value {code '{+ 1 :x}} {pre '{def bar {lambda {:x} {let { {:u {+ 1 :x}} } {+ {pow :u 3} {pow :u 2} :u} }}} -> {def bar {lambda {:x} {let { {:u {+ 1 :x}} } {+ {pow :u 3} {pow :u 2} :u} }}} '{bar 4} -> {bar 4} } _h2 2. triangle's area _p As a second example the area of a triangle [a,b,c] is given by this formula {pre {center area = √{span {@ style="border-top:1px solid #000"}s*(s-a)*(s-b)*(s-c)} with s = (a+b+c)/2 }} _p where {b s} is used four times and should be compute only one. _p A first approach could be to define a first function {code tri1(a,b,c)} precomputing this value {code s = (a+b+c)/2} and calling a second function {code tri2(a,b,c,s)} {pre '{def tri1 {lambda {:a :b :c} {tri2 :a :b :c {/ {+ :a :b :c} 2}} }} -> {def tri1 {lambda {:a :b :c} {tri2 :a :b :c {/ {+ :a :b :c} 2}}}} '{def tri2 {lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }} -> {def tri2 {lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}}} '{tri1 3 4 5} -> {tri1 3 4 5} } _p or in a more compact way {pre '{def tri {def tri.in {lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}}} {lambda {:a :b :c} {tri.in :a :b :c {/ {+ :a :b :c} 2}}}} -> {def tri {def tri.in {lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}}} {lambda {:a :b :c} {tri.in :a :b :c {/ {+ :a :b :c} 2}}}} '{tri 3 4 5} -> {tri 3 4 5} } _p A better code would be to avoid naming the inner function and immediately invoqued it with the arguments of the outer function {code :a :b :c} and the new one {code :s}. {pre '{def triangle {lambda {:a :b :c} {{lambda {:x :y :z :s} // we must define all variables used {sqrt {* :s {- :s :x} {- :s :y} {- :s :z}}} } :a :b :c // and give them the values :a :b :c {/ {+ :a :b :c} 2}} // the value computed once }} -> {def triangle {lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} } :a :b :c {/ {+ :a :b :c} 2}}}} '{triangle 3 4 5} -> {triangle 3 4 5} } _p Note that, lambdas are pure functions and have no free variables having acces to outer ones. Variables used in an inner lambda must be defined as arguments and must be feeded with outer values. A kind of {i manual [[closure]]}. _p The second approach is to use the {code let} special form. We have also to redefine and reassign arguments used in the let's body. {pre '{def triangle2 {lambda {:a :b :c} {let { {:x :a} // :x gets :a, {:y :b} // :x, :y and :z will be used {:z :c} // by the let's body {:s {/ {+ :a :b :c} 2}} // :s is computed once } {sqrt {* :s {- :s :x} {- :s :y} {- :s :z}}} }}} -> {def triangle2 {lambda {:a :b :c} {let { {:x :a} {:y :b} {:z :c} {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :x} {- :s :y} {- :s :z}}} }}} '{triangle2 3 4 5} -> {triangle2 3 4 5} } _p Note that renaming [{code :a, :b, :c}] into [{code :x, :y, :z}] is not mandatory. This is what we would write in Javascript {pre var triangle2 = function( a,b,c ) '{ var x = a, y = b, z = c, s = (a+b+c)/2; return s*(s-x)*(s-y)*(s-z) }; triangle2( 3,4,5 ) } _p Note that Javascript functions create closures and [a,b,c] don't need to be re-affected to local variables [x,y,z]. _h2 3. nested lets _p lets can be nested and, for instance, we can write a function testing the dimensions given for a valid triangle {pre '{def triangle3 {lambda {:a :b :c} {let { {:x :a} {:y :b} {:z :c} {:s {/ {+ :a :b :c} 2}} } {let { {:t {* :s {- :s :x} {- :s :y} {- :s :z}}} } {if {> :t 0} then {sqrt :t} else It's not a valid triangle!} }}}} -> {def triangle3 {lambda {:a :b :c} {let { {:x :a} {:y :b} {:z :c} {:s {/ {+ :a :b :c} 2}} } {let { {:t {* :s {- :s :x} {- :s :y} {- :s :z}}} } {if {> :t 0} then {sqrt :t} else It's not a valid triangle!}}}}} '{triangle3 3 4 5} -> {triangle3 3 4 5} '{triangle3 31 4 5} -> {triangle3 31 4 5} } _p See also an application in [[equation]]! {style ;; pre { box-shadow:0 0 8px #000; padding:5px;} }
lambdaspeech v.20200126