lambdaspeech
::
list2
1
|
list
|
login
|
load
|
|
{div {@ style="font:italic 3.0em optima; text-align:center;"} from roots to canopy} {center maybe a better one [[here| http://lambdaway.free.fr/lambdawalks/?view=fromroots2canopy]]} _h2 introduction _p The '{lambda way} project is a light framework built on a wiki, '{lambda tank}, and a functional programming language, '{lambda talk}. _p In this page, using nothing but two special forms, {code lambda & def}, and a {i quasi}-empty dictionary , we are going to define some data and control structures and explore some interesting structures, {i pairs, lists, arithmetic, graphics }... _h2 1) syntax & evaluation _p Following the λ calculus created in the 30s by Alonzo Church, a lambdatalk expression is defined as follows {center {pre expression := word | abstraction | application | definition }} _p where {pre word := any chars except spaces and '{} evaluated to itself abstraction := '{lambda {words} expression} evaluated to a word (ref) application := '{abstraction expression} evaluated to words definition := '{def word expression} evaluated to a word (name) } _h2 2) lambda _p The command {pre {b replace} :a{sub 0} :a{sub 1} ... a{sub n-1} {b in} expression containing some occurences of :a{sub i} {b by} v{sub 0} v{sub 1} ... v{sub p-1} } _p rewritten in a prefixed parenthesized form {pre °°{{°°lambda °°{°°:a{sub 0} :a{sub 1} ... a{sub n-1}°°}°° expression containing some occurences of :a{sub i}°°}°° v{sub 0} v{sub 1} ... v{sub p-1}°°}°° } _p so called {b IIFE} (Immediately Invoked Function Expression), defines an {i anonymous function} containing a sequence of n arguments {code :a{sub i}}, {i immediately invoked} on a sequence of p values {code v{sub i}}, and returning the expression in its body as so modified: _ul {b if p < n} : _ul20 the occurrences of the p first arguments are replaced in the function's body by the corresponding p given values, _ul20 a function waiting for missing n-p values is created, _ul20 and its reference is returned. _ul20 example: {pre '{{lambda {:x :y} ... :y ... :x ...} hello} -> '{lambda {:y} ... :y ...
hello
...} // replaces :x by hello -> LAMB_123 // the new functions's reference } _ul20 called with the value world this function will return ... world ... hello ... _ul {b if p = n} : _ul20 the occurences of the n arguments are replaced in the function's body by the corresponding p given values, _ul20 the body is evaluated and the result is returned. _ul20 example {pre '{{lambda {:x :y} ... :y ... :x ...} hello world} -> '{{lambda {:y} ... :y ...
hello
...} world} // replaces :x by hello -> '{{lambda {} ...
world
...
hello
...} } // replaces :y by world -> ... world ... hello ... // the value } _ul {b if p > n} : _ul20 the occurrences of the n-1 first arguments are replaced in the function's body by the corresponding n-1 given values, _ul20 the occurrences of the last argument are replaced in the body by the sequence of p-n supernumerary values, _ul20 the body is evaluated and the result is returned. _ul20 example: {pre '{{lambda {:x :y} ... :y ... :x ...} hello
world good morning
} -> '{{lambda {:y} ... :y ... hello ...} world good morning} -> '{{lambda {} ...
world good morning
... hello ...}} -> ... world good morning ... hello ... // the value } _p A lambda has access to user defined constants|functions and eventual built-in primitives, but is a {b pure black box}, totally independent of the context and without any side effect. At the time of invocation, the occurrences of the lambda's arguments {i and they alone} are replaced in the lambda's body by the values provided. Outer lambda's variables are inaccessible. If they are required they must be {i manually redefined} in the inner lambda's list of arguments and their values assigned via an IIFE. _p Lambdas can be deeply nested and expressions be completely unreadable. For convenience we therefore introduce a second special form {code '{def name expression}} which will greatly simplify writing and reading code. This second special form {code def} simply evaluates {code expression}, stores the result in a dictionary (initially empty) and returns {code name} as a reference, a {i constant}. Constants thus defined are global and immutable. Examples: {pre '{def HI hello world} -> {def HI hello world} HI // words are not evaluated -> HI // in a worksheet writing 1+2 displays "1+2" '{HI} // bracketed words are evaluated -> {HI} // in a worksheet writing =1+2 displays "3" '{def swap {lambda {:x :y} :y :x}} -> {def swap {lambda {:x :y} :y :x}} '{swap hello world} -> {swap hello world} } _p Bear in mind that the two last expressions are an other way to write this IIFE: {pre '{{lambda {:x :y} :y :x} hello world} -> world hello } _p What can be done with so little? _h2 3) pairs & lists _p Let's build a set of useful blocks: {pre '{def | {lambda {:a :b} :a}} -> {def | {lambda {:a :b} :a}} '{def ø {lambda {:a :b} :b}} -> {def ø {lambda {:a :b} :b}} '{def [] {lambda {:a :b :c} {:c :a :b}}} -> {def [] {lambda {:a :b :c} {:c :a :b}}} '{def [ {lambda {:c} {:c |}}} -> {def [ {lambda {:c} {:c |}}} '{def ] {lambda {:c} {:c ø}}} -> {def ] {lambda {:c} {:c ø}}} '{def ø? {lambda {:c} {:c {| ]} [}}} -> {def ø? {lambda {:c} {:c {| ]} [}}} } _p We create our first data structure, the {code pair}, a concept due to a student of Alonzo Church, Stephen Cole Kleene: {pre '{def P {[] a b}} -> {def P {[] a b}} // a partial application '{ø? {P}} -> {ø? {P}} '{[ {P}} -> {[ {P}} '{] {P}} -> {] {P}} } _p Note the partial application {code '{def P {[] a b}}} returning a function '{lambda {:c} {:c a b}} waiting for the missing values. The {code [ & ]} functions will {i access} the first and second values {code a & b}. _p We compose pairs to build lists ending with {code ø}. {pre '{def L {[] a {[] b {[] c {[] d {[] e ø}}}}}} -> {def L {[] a {[] b {[] c {[] d {[] e ø}}}}}} } _p Let's access every terms of the list and test rests: {pre '{ø? {L}} -> {ø? {L}} '{[ {L}} & '{ø? {[ {L}}} -> {[ {L}} & {ø? {] {L}}} '{[ {] {L}}} & '{ø? {[ {L}}} -> {[ {] {L}}} & {ø? {] {L}}} '{[ {] {] {L}}}} & '{ø? {] {] {L}}}} -> {[ {] {] {L}}}} & {ø? {] {] {L}}}} '{[ {] {] {] {L}}}}} & '{ø? {] {] {] {L}}}}} -> {[ {] {] {] {L}}}}} & {ø? {] {] {] {L}}}}} '{[ {] {] {] {] {L}}}}}} & '{ø? {] {] {] {] {L}}}}}} -> {[ {] {] {] {] {L}}}}}} & {ø? {] {] {] {] {L}}}}}} '{ø? {] {] {] {] {] {L}}}}}}} -> {ø? {] {] {] {] {] {L}}}}}}} } _p Sounds a recursive process! _h2 4) recursion {pre '{def l.disp {lambda {:l} {{{ø? :l} {[] {lambda {:l} } {lambda {:l} {[ :l} {l.disp {] :l}}}}} :l}}} -> {def l.disp {lambda {:l} {{{ø? :l} {[] {lambda {:l} } {lambda {:l} {[ :l} {l.disp {] :l}}}}} :l}}} '{def l.length {lambda {:l} {{{ø? :l} {[] {lambda {:l} } {lambda {:l} .{l.length {] :l}}}}} :l}}} -> {def l.length {lambda {:l} {{{ø? :l} {[] {lambda {:l} } {lambda {:l} .{l.length {] :l}}}}} :l}}} '{def l.rev {def l.rev.r {lambda {:a :b} {{{ø? :a} {[] {lambda {:a :b} :b} {lambda {:a :b} {l.rev.r {] :a} {[] {[ :a} :b}}}}} :a :b}}} {lambda {:a} {l.rev.r :a ø}}} -> {def l.rev {def l.rev.r {lambda {:a :b} {{{ø? :a} {[] {lambda {:a :b} :b} {lambda {:a :b} {l.rev.r {] :a} {[] {[ :a} :b}}}}} :a :b}}} {lambda {:a} {l.rev.r :a ø}}} '{l.disp {L}} -> {l.disp {L}} '{l.disp {l.rev {L}}} -> {l.disp {l.rev {L}}} '{l.length {L}} -> {l.length {L}} } _p It may be interesting to know that all these recursive algorithms can be written as true λ calculus expressions exclusively made of words, abstractions and applications, in other words without using the second special form. The trouble is that the body of a recursive function contains its name! As a workaround we will add a new argument, {code :f}, acting as a {i fix point} and call the new {i almost-recusive} function with some {code Y} combinator acting as a {i bridge}. _p Let's apply this process to the {code l.disp} function: {pre 1) adding a new argument, the fix-point: '{def almost.disp {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}}} -> {def almost.disp {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}}} 2) defining the bridge: '{def Y {lambda {:f :n} {:f :f :n}}} -> {def Y {lambda {:f :n} {:f :f :n}}} 3) composing boths: '{Y almost.disp {L}} -> {Y almost.disp {L}} } _p We can {i glue} {code Y} and {code almost_disp} into {code Y.disp}: {pre '{def Y.disp {lambda {:l} {{lambda {:f :n} {:f :f :n}} {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}} :l }}} -> {def Y.disp {lambda {:l} {{lambda {:f :n} {:f :f :n}} {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}} :l }}} '{Y.disp {L}} -> {Y.disp {L}} } _p forget the name {code Y.disp}, building an IIFE: {pre '{{lambda {:l} {{lambda {:f :n} {:f :f :n}} {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}} :l }} {L}} -> {{lambda {:l} {{lambda {:f :n} {:f :f :n}} {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} } {lambda {:f :l} {[ :l} {almost.disp :f {] :l}}}}} :f :l}} :l }} {L}} } _p and, replacing names by their lambda expressions, build this deeply nested expression: {pre '{{lambda {:n} {{lambda {:f :n} {:f :f :n}} {lambda {:f :n} {{{{lambda {:z} {:z {{lambda {:x :y} :x} {lambda {:z} {:z {lambda {:x :y} :y}}}} {lambda {:z} {:z {lambda {:x :y} :x}}}}} :n} {{lambda {:x :y :z} {:z :x :y}} {lambda {:f :n} } {lambda {:f :n} {{lambda {:z} {:z {lambda {:x :y} :x}}} :n} {:f :f {{lambda {:z} {:z {lambda {:x :y} :y}}} :n}} } }} :f :n}} :n}} {{lambda {:x :y :z} {:z :x :y}} a {{lambda {:x :y :z} {:z :x :y}} b {{lambda {:x :y :z} {:z :x :y}} c {{lambda {:x :y :z} {:z :x :y}} d {{lambda {:x :y :z} {:z :x :y}} e {lambda {:x :y} :y}}}}}}} -> a b c d e } _p In a pure λ-calculus style! _h2 5) applications _h3 5.1) towers of hanoï {pre '{def hanoi {lambda {:n :from :to :via} {{{ø? :n} {[] {lambda {:n :from :to :via} } {lambda {:n :from :to :via} {hanoi {] :n} :from :via :to} {br} move {l.length :n} from tower :from to tower :to {hanoi {] :n} :via :to :from} }}} :n :from :to :via}}} -> {def hanoi {lambda {:n :from :to :via} {{{ø? :n} {[] {lambda {:n :from :to :via} } {lambda {:n :from :to :via} {hanoi {] :n} :from :via :to} {br} move {l.length :n} from tower :from to tower :to {hanoi {] :n} :via :to :from} }}} :n :from :to :via}}} '{hanoi {L} A B C} -> {hanoi {L} A B C} } _h3 5.2) hilbert's curve {pre '{def left {lambda {:d :n} {{{ø? :n} {[] {lambda {:d :n} } {lambda {:d :n} T90 {right :d {] :n}} M:d T-90 {left :d {] :n}} M:d {left :d {] :n}} T-90 M:d {right :d {] :n}} T90 }}} :d :n}}} -> {def left {lambda {:d :n} {{{ø? :n} {[] {lambda {:d :n} } {lambda {:d :n} T90 {right :d {] :n}} M:d T-90 {left :d {] :n}} M:d {left :d {] :n}} T-90 M:d {right :d {] :n}} T90 }}} :d :n}}} '{def right {lambda {:d :n} {{{ø? :n} {[] {lambda {:d :n} } {lambda {:d :n} T-90 {left :d {] :n}} M:d T90 {right :d {] :n}} M:d {right :d {] :n}} T90 M:d {left :d {] :n}} T-90 }}} :d :n}}} -> {def right {lambda {:d :n} {{{ø? :n} {[] {lambda {:d :n} } {lambda {:d :n} T-90 {left :d {] :n}} M:d T90 {right :d {] :n}} M:d {right :d {] :n}} T90 M:d {left :d {] :n}} T-90 }}} :d :n}}} '{{SVG} {curve #000 5 5 0 {left 10 {L}}} } } {center {{SVG} {curve #000 5 5 0 {left 10 {L}}} } } _h3 5.3) tree {pre '{def tree {lambda {:e :s :k :a :b} {{{ø? :k} {[] {lambda {:e :s :k :a :b} T-30 M:e T120 M:e T120 M:e T150} {lambda {:e :s :k :a :b} M:s T:a {tree :e :s {] :k} :a :b} T-:a T-:b {tree :e :s {] :k} :a :b} T:b M-:s}}} :e :s :k :a :b}}} -> {def tree {lambda {:e :s :k :a :b} {{{ø? :k} {[] {lambda {:e :s :k :a :b} T-30 M:e T120 M:e T120 M:e T150} {lambda {:e :s :k :a :b} M:s T:a {tree :e :s {] :k} :a :b} T-:a T-:b {tree :e :s {] :k} :a :b} T:b M-:s}}} :e :s :k :a :b}}} } {pre '{{SVG} {curve #f00 150 250 180 {tree 10 50 {L} 45 45}} {curve #0f0 160 290 180 {tree 10 60 {L} 30 50}} {curve #00f 140 310 180 {tree 10 60 {L} 20 50}} } } {center {{SVG} {curve #f00 150 250 180 {tree 10 50 {L} 45 45}} {curve #0f0 160 290 180 {tree 10 60 {L} 30 50}} {curve #00f 140 310 180 {tree 10 60 {L} 20 50}} } {{hide} {def SVG svg {@ width="320" height="320" style="box-shadow:0 0 8px #000"}} {def curve {lambda {:c :s} {path {@ d="M {turtle :s}" stroke=":c" stroke-width="1" fill="transparent"}} }}} } _h3 5.4) arithmetic {pre '{def zero {lambda {:f :x} :x}} -> {def zero {lambda {:f :x} :x}} '{def one {lambda {:f :x} {:f :x}}} -> {def one {lambda {:f :x} {:f :x}}} '{def two {lambda {:f :x} {:f {:f :x}}}} -> {def two {lambda {:f :x} {:f {:f :x}}}} '{def three {lambda {:f :x} {:f {:f {:f :x}}}}} -> {def three {lambda {:f :x} {:f {:f {:f :x}}}}} '{def four {lambda {:f :x} {:f {:f {:f {:f :x}}}}}} -> {def four {lambda {:f :x} {:f {:f {:f {:f :x}}}}}} '{def five {lambda {:f :x} {:f {:f {:f {:f {:f :x}}}}}}} -> {def five {lambda {:f :x} {:f {:f {:f {:f {:f :x}}}}}}} '{def church {lambda {:n} {{:n {lambda {:x} {+ :x 1}}} 0}}} -> {def church {lambda {:n} {{:n {lambda {:x} {+ :x 1}}} 0}}} '{def succ {lambda {:n :f :x} {:f {:n :f :x}}}} -> {def succ {lambda {:n :f :x} {:f {:n :f :x}}}} '{def add {lambda {:n :m :f :x} {{:n :f} {:m :f :x}}}} -> {def add {lambda {:n :m :f :x} {{:n :f} {:m :f :x}}}} '{def mul {lambda {:n :m :f :x} {:n {:m :f} :x}}} -> {def mul {lambda {:n :m :f :x} {:n {:m :f} :x}}} '{def power {lambda {:n :m :f :x} {{:m :n :f} :x}}} -> {def power {lambda {:n :m :f :x} {{:m :n :f} :x}}} '{def pred {lambda {:n} {[ {{:n {lambda {:p} {[] {] :p} {succ {] :p}}}}} {[] zero zero}}}}} -> {def pred {lambda {:n} {[ {{:n {lambda {:p} {[] {] :p} {succ {] :p}}}}} {[] zero zero}}}}} '{def subtract {lambda {:m :n} {{:n pred} :m}}} -> {def subtract {lambda {:m :n} {{:n pred} :m}}} '{def ifac {lambda {:n} {] {{:n {lambda {:p} {[] {succ {[ :p}} {mul {[ :p} {] :p}}}}} {[] one one}}}}} -> {def ifac {lambda {:n} {] {{:n {lambda {:p} {[] {succ {[ :p}} {mul {[ :p} {] :p}}}}} {[] one one}}}}} '{def rfac {lambda {:n} {{{ø? :n} {[] {lambda {:n} one} {lambda {:n} {mul :n {rfac {pred :n}}}}}} :n}}} -> {def rfac {lambda {:n} {{{ø? :n} {[] {lambda {:n} one} {lambda {:n} {mul :n {rfac {pred :n}}}}}} :n}}} '{church zero} -> {church zero} '{church one} -> {church one} '{church {succ one}} -> {church {succ one}} '{church {pred one}} -> {church {pred one}} '{church {pred zero}} -> {church {pred zero}} // nothing before zero '{church {add two five}} -> {church {add two five}} '{church {subtract five two}} -> {church {subtract five two}} '{church {subtract two five}} -> {church {subtract two five}} // nothing before zero '{church {mul two five}} -> {church {mul two five}} '{church {power two five}} -> {church {power two five}} '{church {ifac five}} -> {church {ifac five}} '{church {rfac five}} -> {church {rfac five}} '{church {ifac {mul two four}}} -> 40320 in 1240ms '{church {rfac {mul two four}}} -> 40320 in 1240ms waiting for //, %% and gcd ... } _h3 5.5) serie, map, reduce {prewrap '{def l.serie {lambda {:a :b} {{{ø? {subtract :b :a}} {[] {lambda {:a :b} {[] :b ø}} {lambda {:a :b} {[] :a {l.serie {succ :a} :b}} }}} :a :b}}} -> {def l.serie {lambda {:a :b} {{{ø? {subtract :b :a}} {[] {lambda {:a :b} {[] :b ø}} {lambda {:a :b} {[] :a {l.serie {succ :a} :b}} }}} :a :b}}} '{def l.map {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} ø} {lambda {:f :l} {[] {:f {[ :l}} {l.map :f {] :l}}}}}} :f :l}}} -> {def l.map {lambda {:f :l} {{{ø? :l} {[] {lambda {:f :l} ø} {lambda {:f :l} {[] {:f {[ :l}} {l.map :f {] :l}}}}}} :f :l}}} '{def l.reduce {def l.reduce.r {lambda {:f :a :b} {{{ø? :a} {[] {lambda {:f :a :b} :b} {lambda {:f :a :b} {:f {[ :a} {l.reduce.r :f {] :a} :b}}}}} :f :a :b}}} {lambda {:f :a} {l.reduce.r :f :a {[ :a}}}} -> {def l.reduce {def l.reduce.r {lambda {:f :a :b} {{{ø? :a} {[] {lambda {:f :a :b} :b} {lambda {:f :a :b} {:f {[ :a} {l.reduce.r :f {] :a} :b}}}}} :f :a :b}}} {lambda {:f :a} {l.reduce.r :f :a {[ :a}}}} '{l.disp {l.map del {L}}} -> {l.disp {l.map del {L}}} '{l.disp {l.map church {l.serie one five}}} -> {l.disp {l.map church {l.serie one five}}} '{l.disp {l.map church {l.map {lambda {:x} {power four :x}} {l.serie one five}}}} -> {l.disp {l.map church {l.map {lambda {:x} {power four :x}} {l.serie one five}}}} '{church {l.reduce add {l.serie zero {mul two five}}}} -> {church {l.reduce add {l.serie zero {mul two five}}}} '{church {l.reduce mul {l.serie one {mul two five}}}} -> 3628800 (23500ms) } _h2 conclusion _p The {b read & replace} implementation of lambdatalk makes its evaluator work in direct contact with the raw code and in two steps: _ul 1) abstraction: special forms (lambda def ...) are replaced by words, eg: {pre '{def add {lambda {x y} {+ x y}}} -> '{def add LAMB_123} -> add } _ul 2) application: normal (nested) forms are replaced "from inside out" by words, eg: {pre '{sqrt {+ {* 3 3} {* 4 4}}} -> '{sqrt {+ 9 16}} -> '{sqrt 25} -> 5 } _ul and the evaluation stops when the code contains only words. _p Note that lambdas (first class) are also created and evaluated in the application step, in the case of partial applications. _p During the first step, the raw code (the initial string) is immediately reduced to a smaller sequence of words, some of which are pointers to functions that contain substrings that contain pointers to functions ... and so on, recursively. _p During the second step, it is in this {b tree of strings and substrings} that the evaluations of normal (nested) forms are carried out independently. It's the reason why the computation of a Fibonacci function inserted in the middle of a page of one million words is not affected by its length. And since {b functions are really independent of any context} - no lexical context, no closure - one could even think of a parallel evaluation, for instance defining lambdas (at least some of them) as [[web-workers|?view=webworker6]]. _p It's all reminiscent of a {i Turing machine}, with its infinite stripe on which a window comes and goes... _h2 references _ul [[https://harryrschwartz.com/2017/07/26/lifting-lambdas-into-supercompilers| https://harryrschwartz.com/2017/07/26/lifting-lambdas-into-supercompilers]] _ul [[https://harryrschwartz.com/2017/07/26/lifting-lambdas-into-supercompilers| https://harryrschwartz.com/2017/07/26/lifting-lambdas-into-supercompilers]] _ul [[https://en.wikipedia.org/wiki/Combinatory_logic| https://en.wikipedia.org/wiki/Combinatory_logic]] _ul [[History-of-lambda-calculus-and-combinatory-logic.pdf| https://www.researchgate.net/profile/J_Hindley/publication/228386842_History_of_lambda-calculus_and_combinatory_logic/links/5ac9e3aaaca272abdc6158c4/History-of-lambda-calculus-and-combinatory-logic.pdf?origin=publication_detail]] _ul [[https://en.wikipedia.org/wiki/Lambda_lifting| https://en.wikipedia.org/wiki/Lambda_lifting]] _ul [[https://wiki.haskell.org/Super_combinator| https://wiki.haskell.org/Super_combinator]] {style #page_content { font-family:optima; } pre { box-shadow:0 0 8px #000; padding:5px; } }
lambdaspeech v.20200126