+
1
|
skin
|
login
|
edit
workshop
::
factory
user:anonymous
{LAFABRIQUE} {center {i La Sagrada Familia, Antonio Gaudi, Barcelona{br} Single rules can generate beautiful complexities. }} _h2 abstract {div {COLUMNS} _p We progressively build a web functional programming language, '{lambda talk}, inspired by the λ-calculus. With a reduced set of 3 operators, {b abstraction, application, definition} working on words, we create data structures, pairs, lists and recursive processes, we create numbers and their associate operators and finally, we take benefit of the powerful capabilities of modern browsers to improve the readabilty and code efficiency. '{lambda talk} works in '{lambda tank}, a 50kb zipped "Interactive Development Environment" without any external dependencies and thereby easy to download and install on any web account provider running PHP. } _h2 introduction {div {COLUMNS} _p The goal is to {b build a computer language} on the smallest foundations. Our working environment will be any web browser on any system hosting a very simple text editor, a wiki called '{lambda tank}. _p Following the first {b wiki} created in 1995 by {b Ward Cunningham} hundred of wikis have moved us fom simple consumers to creators of sharable informations. But these tools come generally with rather rudimentary and heterogeneous syntaxes to enter, enrich and structure texts. '{lambda tank} comes with a true programming language, '{lambda talk}, allowing not only to enter, enrich and structure text, but also to {b write code}. _p Computer languages are generally introduced from a long enumeration of their syntaxic rules, from objects and their associated functions - strings, numbers, arrays, ... - and via numerous examples. We can learn how to resolve problems not to understand the way languages have been conceived. There remains a great deal of mystery which can only be lifted by those who have had access to their fabrication. _p It's what we are going to do. We are going to build '{lambda talk} from the most elementary bricks. A handful of rules, no grey area, no magical functions, no abstract concepts. Nothing but words to assemble/compose, which could be manipulated by hand, without any computer. _p Let's introduce '{lambda talk}, quickly. } _h2 1. '{lambda talk}'s foundations {img {@ src="data/brussels/mies_pav.jpg" width="100%"}} {center {i Barcelona Pavilion | Mies van der Rohe {br} The Maxwell's equations of Architecture}} {div {COLUMNS} _p Imagine a machine which understands this question: {pre {b replace} "fruit" and "unknown" {b in} "The color of fruits is unknwon." {b by} "apple" and "green" } _p and returns {pre The color of apples is green. } _p '{lambda talk} is such a {b replacement machine} where this question is formulated using a slightly different syntax: {pre '{{lambda {fruit unknown} The color of fruits is unknown.} apple green} } _p This {i rather strange} syntax is freely inspired by the '{λ calculus} created in the 1930s by {b Alonzo Church}. In '{lambda talk} a valid expression is made of a reduced set of {b nested terms}, [{code words,abstractions,applications}] and is evaluated to {b words}. More precisely: {pre {WRAP} 1. a {b word} is a group of any characters except spaces and curly braces '{}, and is not evaluated, } {pre {WRAP} 2. an {b abstraction}, a special form written '{lambda {words} expression}, is evaluated to a word referencing an anonymous function selecting words (arguments) in expression (body) to be replaced by some future given words (values), } {pre {WRAP} 3. an {b application}, a nested form written '{expression1 expression2}, first evaluates expression1 to the reference of an abstraction and expression2 to words2. The abstraction replaces its arguments in its body by the given words2 and returns some words3, } _p For convenience a second special form, {code definition}, is added: {pre {WRAP} 4. a {b definition}, a special form written '{def word expression}, returns word (the name) bound to expression (first evaluated to words) in a dictionary initially empty. } _p {b Abstractions} and {b definitions} are {i special forms} evaluated in a call by name {b lazy} mode. They can be nested. {b Applications} are {i simple forms} evaluated from inside out, in a call by value {b eager} mode. Functions don't create closures but accept {i de facto} partial calls, memorizing the given values and returning a new function waiting for the rest. _p With this reduced set of tools we have built the foundations of a {b Turing complete programming language}, '{lambda talk}, working in a tiny wiki, '{lambda tank}, as a light overlay on top of any web browser. We are going to explore '{lambda talk}'s capabilities playing with words, numbers and more. } _h2 2. '{lambda words} {img {@ src="data/brussels/bibliotheque_virtuelle.jpg" width="100%"}} {center An infinity of words.} {div {COLUMNS} _h4 2.1. basics _p Out of braces words are not evaluated. Quoting sequences of words is useless. {pre Hello World -> Hello World } _p Sequences of words can be given a name {pre '{def HI Hello World} -> {def HI Hello World} HI, I just say '{HI} -> HI, I just say {HI} } _p Note that writing {b HI} displays {b HI}. You must write {b '{HI}} to get its value, {b {HI}}. _p Anonymous functions can be created and immediately called {pre '{{lambda {fruit unknown} The color of fruits is unknown.} apple green} -> {{lambda {fruit unknown} The color of fruits is unknown.} apple green} } _p Anonymous functions can be given a name {pre '{def AFFIRMATION {lambda {fruit unknown} The color of fruits is unknown.}} -> {def AFFIRMATION {lambda {fruit unknown} The color of fruits is unknown.}} '{AFFIRMATION apple green} -> {AFFIRMATION apple green} '{AFFIRMATION banana yellow} -> {AFFIRMATION banana yellow} } _h4 2.2 data structures _p Lambdas can be nested and partially called, allowing to build data structures and their associated selectors, beginning with {b pairs} {pre '{def PAIR {lambda {:x :y :z} {:z :x :y}}} -> {def PAIR {lambda {:x :y :z} {:z :x :y}}} '{def LEFT {lambda {:z} {:z {lambda {:x :y} :x}}}} -> {def LEFT {lambda {:z} {:z {lambda {:x :y} :x}}}} '{def RIGHT {lambda {:z} {:z {lambda {:x :y} :y}}}} -> {def RIGHT {lambda {:z} {:z {lambda {:x :y} :y}}}} '{LEFT {PAIR Hello World}} -> {LEFT {PAIR Hello World}} '{RIGHT {PAIR Hello World}} -> {RIGHT {PAIR Hello World}} } _p How does it work? {note_start trace {b Please click me!}} {note_end {@ id="trace"} _p Tracing '{LEFT {PAIR Hello World}} -> Hello {pre '{{lambda {:c} {:c {lambda {:a :b} :a}}} {{lambda {:a :b :c} {:c :a :b}} Hello World}} -> {{lambda {:c} {:c {lambda {:a :b} :a}}} {{lambda {:a :b :c} {:c :a :b}} Hello World}} _h6 1) abstractions create anonymous functions 1: '{def abstract_0 {lambda {:a :b} :a}} -> {def abstract_0 {lambda {:a :b} :a}} '{{lambda {:c} {:c abstract_0}} {{lambda {:a :b :c} {:c :a :b}} Hello World}} -> {{lambda {:c} {:c abstract_0}} {{lambda {:a :b :c} {:c :a :b}} Hello World}} 2: '{def abstract_1 {lambda {:c} {:c abstract_0}}} -> {def abstract_1 {lambda {:c} {:c abstract_0}}} '{abstract_1 {{lambda {:a :b :c} {:c :a :b}} Hello World}} -> {abstract_1 {{lambda {:a :b :c} {:c :a :b}} Hello World}} 3: '{def abstract_2 {lambda {:a :b :c} {:c :a :b}}} -> {def abstract_2 {lambda {:a :b :c} {:c :a :b}}} '{abstract_1 {abstract_2 Hello World}} -> {abstract_1 {abstract_2 Hello World}} 4: '{def abstract_3 {lambda {:c} {:c Hello World}}} -> {def abstract_3 {lambda {:c} {:c Hello World}}} '{abstract_1 abstract_3} -> {abstract_1 abstract_3} 5: '{{lambda {:c} {:c abstract_0}} abstract_3} -> {{lambda {:c} {:c abstract_0}} abstract_3} _h6 2) applications using the anonymous functions 6: '{abstract_3 abstract_0} -> {abstract_3 abstract_0} 7: '{{lambda {:c} {:c Hello World}} abstract_0} -> {{lambda {:c} {:c Hello World}} abstract_0} 8: '{abstract_0 Hello World} -> {abstract_0 Hello World} 9: '{{lambda {:a :b} :a} Hello World} -> {{lambda {:a :b} :a} Hello World} 10: Hello 11: no more curly braces -> stop! } } _p In the followings we will systematically prefix arguments with a colon, {b :args}, enlighting their locality and for technical reasons: they are used as {b regular expressions} in the function's internal replacement process. The key point is that the intersection of arguments names must be null, for instance {b '{:t0 :t1}} is a valid list of arguments, {b '{:t :t0 :t1}} is not. To sum up, A "variable" defined with {code '{def name expression}} is global, constant, immutable, and its value is called between curly braces. A variable defined as a functions' argument is local to the function, mutable and is prefixed by a colon, {b :arg}. _p Pairs can be composed to create trees and lists {pre '{def REPUBLIC {PAIR Liberty {PAIR Equality {PAIR Fraternity {PAIR Laïcity NIL}}}}} // more about NIL later -> {def REPUBLIC {PAIR Liberty {PAIR Equality {PAIR Fraternity {PAIR Laïcity NIL}}}}} '{LEFT {REPUBLIC}} -> {LEFT {REPUBLIC}} '{LEFT {RIGHT {REPUBLIC}}} -> {LEFT {RIGHT {REPUBLIC}}} '{LEFT {RIGHT {RIGHT {REPUBLIC}}}} -> {LEFT {RIGHT {RIGHT {REPUBLIC}}}} '{LEFT {RIGHT {RIGHT {RIGHT {REPUBLIC}}}}} -> {LEFT {RIGHT {RIGHT {RIGHT {REPUBLIC}}}}} } _h4 2.3. control structures _p Two functions will help to display lists in a loop {pre '{def NIL {lambda {:f :x} :x}} -> {def NIL {lambda {:f :x} :x}} '{def ISNIL {lambda {:n} {:n {lambda {:x} RIGHT} LEFT}}} -> {def ISNIL {lambda {:n} {:n {lambda {:x} RIGHT} LEFT}}} '{def LIST.DISPLAY {lambda {:list} {{{ISNIL :list} // if last item is NIL {PAIR {lambda {:list} } // do nothing, stop, else {lambda {:list} // get left, recurse on right {LEFT :list} {LIST.DISPLAY {RIGHT :list}}}}} :list}}} -> {def LIST.DISPLAY {lambda {:list} {{{ISNIL :list} {PAIR {lambda {:list} } {lambda {:list} {LEFT :list} {LIST.DISPLAY {RIGHT :list}}}}} :list}}} '{ISNIL NIL} -> {ISNIL NIL} // true '{ISNIL {REPUBLIC}} -> {ISNIL {REPUBLIC}} // false '{LIST.DISPLAY {REPUBLIC}} -> {LIST.DISPLAY {REPUBLIC}} } _p Note that, thanks to the data structure [PAIRS, LEFT, RIGHT] and a "zest" of lambdas introducing {b laziness}, we could define a {b recursive algorithm} without any {b '{IF THEN ELSE}} boolean special form, not to speak of any Y-combinator. } _h2 3. '{lambda numbers} {img {@ src="data/brussels/operators.jpg" width="100%"}} {center {i code is data, data is code}} {div {COLUMNS} _p We can reinvent some elements of arithmetic. _h4 3.1. defining and displaying numbers _p After Giuseppe Peano and Alonzo CHURCH, we define the set of natural number, {b N}, as the "number" {b NIL} and its successors, {b '{SUCC {SUCC {SUCC ... n times ...{NIL}}}}}. {pre '{def SUCC {lambda {:n :f :x} {:f {{:n :f} :x}}}} -> {def SUCC {lambda {:n :f :x} {:f {{:n :f} :x}}}} '{def ZERO NIL} -> {def ZERO NIL} // ZERO is equivalent to NIL '{def ONE {SUCC {ZERO}}} -> {def ONE {SUCC {ZERO}}} '{def TWO {SUCC {ONE}}} -> {def TWO {SUCC {ONE}}} '{def THREE {SUCC {TWO}}} -> {def THREE {SUCC {TWO}}} '{def FOUR {SUCC {THREE}}} -> {def FOUR {SUCC {THREE}}} '{def FIVE {SUCC {FOUR}}} -> {def FIVE {SUCC {FOUR}}} ... and so on } _p Calling {b '{FIVE}} returns {FIVE}, it's the reference of an anonymous function. We have to define a function to display numbers in a more familiar shape. At this point numbers don't exist and we will define a function CHURCH to display numbers in a unary numeral notation, {code ['|, '||, '|||, '||||, ... ]}. For a better readability, forgetting that JS numbers and the + operator are not supposed to exist at this point, we also define a function DECIM to display numbers in the decimal notation, {code 0, 1, 2, 3, ...}. {pre '{def CHURCH {lambda {:n} {{:n {lambda {:x} :x|}} '}}} -> {def CHURCH {lambda {:n} {{:n {lambda {:x} :x|}} '}}} '{def DECIM {lambda {:n} {{:n {lambda {:x} {+ :x 1}}} 0}}} -> {def DECIM {lambda {:n} {{:n {lambda {:x} {+ :x 1}}} 0}}} '{CHURCH {ZERO}} -> {CHURCH {ZERO}} or '{DECIM {ZERO}} -> {DECIM {ZERO}} '{CHURCH {ONE}} -> {CHURCH {ONE}} or '{DECIM {ONE}} -> {DECIM {ONE}} '{CHURCH {TWO}} -> {CHURCH {TWO}} or '{DECIM {TWO}} -> {DECIM {TWO}} '{CHURCH {THREE}} -> {CHURCH {THREE}} or '{DECIM {THREE}} -> {DECIM {THREE}} '{CHURCH {FOUR}} -> {CHURCH {FOUR}} or '{DECIM {FOUR}} -> {DECIM {FOUR}} '{CHURCH {FIVE}} -> {CHURCH {FIVE}} or '{DECIM {FIVE}} -> {DECIM {FIVE}} } _h4 3.2. a set of operators {pre '{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 MULT {lambda {:n :m :f :x} {:n {:m :f} :x}}} -> {def MULT {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}}} '{CHURCH {ADD {TWO} {THREE}}} -> {CHURCH {ADD {TWO} {THREE}}} // 5 '{CHURCH {MULT {TWO} {THREE}}} -> {CHURCH {MULT {TWO} {THREE}}} // 6 '{CHURCH {POWER {TWO} {THREE}}} -> {CHURCH {POWER {TWO} {THREE}}} // 8 '{def PRED {def PRED.PAIR {lambda {:p} {PAIR {RIGHT :p} {SUCC {RIGHT :p}}}}} {lambda {:n} {LEFT {{:n PRED.PAIR} {PAIR {ZERO} {ZERO}}}}}} -> {def PRED {def PRED.PAIR {lambda {:p} {PAIR {RIGHT :p} {SUCC {RIGHT :p}}}}} {lambda {:n} {LEFT {{:n PRED.PAIR} {PAIR {ZERO} {ZERO}}}}}} '{def SUBTRACT {lambda {:m :n} {{:n PRED} :m}}} -> {def SUBTRACT {lambda {:m :n} {{:n PRED} :m}}} '{CHURCH {PRED {ZERO}}} -> {CHURCH {PRED {ZERO}}} // 0 numbers can't be negative '{CHURCH {PRED {ONE}}} -> {CHURCH {PRED {ONE}}} // 0 '{CHURCH {PRED {THREE}}} -> {CHURCH {PRED {THREE}}} // 2 '{CHURCH {SUBTRACT {THREE} {TWO}}} -> {CHURCH {SUBTRACT {THREE} {TWO}}} // 1 } _h4 3.3. recursion {pre '{def FAC {lambda {:n} {{{ISNIL :n} {PAIR {lambda {:n} {ONE}} {lambda {:n} {MULT :n {FAC {PRED :n}}}}}} :n}}} -> {def FAC {lambda {:n} {{{ISNIL :n} {PAIR {lambda {:n} {ONE}} {lambda {:n} {MULT :n {FAC {PRED :n}}}}}} :n}}} } {pre {WRAP} '{CHURCH {FAC {ZERO}}} -> {CHURCH {FAC {ZERO}}} // 1 '{CHURCH {FAC {THREE}}} -> {CHURCH {FAC {THREE}}} // 6 '{CHURCH {FAC {MULT {TWO} {TWO}}}} -> {CHURCH {FAC {MULT {TWO} {TWO}}}} '{DECIM {FAC {ADD {TWO} {THREE}}}} -> 120 } _p We could now write a faster tail-recursive algorithm, play with memoïzation and more, but we choose to focus on a strange operator generally used to introduce recursion in &lambda-calculus. _h4 3.4. the Y-combinator _p It's theoretically interesting to build recursion in a pure λ-calculus style reduced to abstractions and applications working on words. Here comes the Y-combinator! {pre '{def Y {lambda {:g :n} {:g :g :n}}} -> {def Y {lambda {:g :n} {:g :g :n}}} '{def ALMOST_FAC {lambda {:g :n} {{{ISNIL :n} {PAIR {lambda {:g :n} {ONE}} {lambda {:g :n} {MULT :n {:g :g {PRED :n}}} } }} :g :n}}} -> {def ALMOST_FAC {lambda {:g :n} {{{ISNIL :n} {PAIR {lambda {:g :n} {ONE}} {lambda {:g :n} {MULT :n {:g :g {PRED :n}}} } }} :g :n}}} '{DECIM {Y ALMOST_FAC {FIVE}}} -> 120 } _p Recursion has been avoided. We now compose {b Y and ALMOST_FAC}, define and immediately call the anonymous function, and finally skip the names to get a pure λ-calculus expression. {pre '{def YFAC {lambda {:n} {{lambda {:g :n} {:g :g :n}} {lambda {:g :n} {{{ISNIL :n} {PAIR {lambda {:g :n} {ONE}} {lambda {:g :n} {MULT :n {:g :g {PRED :n}}} } }} :g :n }} :n}}} -> {def YFAC {lambda {:n} {{lambda {:g :n} {:g :g :n}} {lambda {:g :n} {{{ISNIL :n} {PAIR {lambda {:g :n} {ONE}} {lambda {:g :n} {MULT :n {:g :g {PRED :n}}} } }} :g :n }} :n}}} '{DECIM {YFAC {FIVE}}} -> 120 '{DECIM {{lambda {:n} {{lambda {:g :n} {:g :g :n}} {lambda {:g :n} {{{ISNIL :n} {PAIR {lambda {:g :n} {ONE}} {lambda {:g :n} {MULT :n {:g :g {PRED :n}}} } }} :g :n }} :n}} {FIVE}}} -> 120 } _p And now the pure λ-calculus expression {pre {WRAP} '{{lambda {:n} {{:n {lambda {:x} :x|}} '}} {{lambda {:n} {{lambda {:g :n} {:g :g :n}} {lambda {:g :n} {{{{lambda {:n} {:n {lambda {:x} {lambda {:z} {:z {lambda {:x :y} :y}}}} {lambda {:z} {:z {lambda {:x :y} :x}}}}} :n} {{lambda {:x :y :z} {:z :x :y}} {lambda {:g :n} {lambda {:f :x} {:f :x}}} {lambda {:g :n} {{lambda {:n :m :f :x} {:n {:m :f} :x}} :n {:g :g {{lambda {:n} {{lambda {:z} {:z {lambda {:x :y} :x}}} {{:n {lambda {:p} {{lambda {:x :y :z} {:z :x :y}} {{lambda {:z} {:z {lambda {:x :y} :y}}} :p} {{lambda {:n :f :x} {:f {{:n :f} :x}}} {{lambda {:z} {:z {lambda {:x :y} :y}}} :p}}}}} {{lambda {:x :y :z} {:z :x :y}} {lambda {:f :x} :x} {lambda {:f :x} :x}}}}} :n}}}}}} :g :n }} :n}} {lambda {:f :x} {:f {:f {:f {:f {:f :x}}}}}}}} -> '|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| } _h4 3.5. the DIV operator _p We can now build some DIV operator returning the integer part and the rest of the division. {pre '{def DIV {def DIV.r {lambda {:a :b :q :r} {{{ISNIL {SUBTRACT {MULT :b :q} :a}} {PAIR {lambda {:a :b :q :r} {DIV.r :a :b {SUCC :q} {SUBTRACT :a {MULT :b :q}}}} {lambda {:a :b :q :r} {PAIR {PRED :q} :r}} }} :a :b :q :r} }} {lambda {:a :b} {{lambda {:d} [{DECIM {LEFT :d}} {DECIM {RIGHT :d}}]} {DIV.r :a :b {ZERO} :b}} }} -> {def DIV {def DIV.r {lambda {:a :b :q :r} {{{ISNIL {SUBTRACT {MULT :b :q} :a}} {PAIR {lambda {:a :b :q :r} {DIV.r :a :b {SUCC :q} {SUBTRACT :a {MULT :b :q}}}} {lambda {:a :b :q :r} {PAIR {PRED :q} :r} } }} :a :b :q :r} }} {lambda {:a :b} {{lambda {:d} [{DECIM {LEFT :d}} {DECIM {RIGHT :d}}]} {DIV.r :a :b {ZERO} :b}} }} '{DIV {ZERO} {TWO}} -> [0 0] // 0 = 2 * 0 + 0 '{DIV {ONE} {TWO}} -> [0 1] // 1 = 2 * 0 + 1 '{DIV {TWO} {TWO}} -> [1 0] // 2 = 2 * 1 + 0 '{DIV {THREE} {TWO}} -> [1 1] // 3 = 2 * 1 + 1 '{DIV {FOUR} {TWO}} -> [2 0] // 4 = 2 * 2 + 0 '{DIV {FIVE} {TWO}} -> [2 1] // 5 = 2 * 2 + 1 } _h4 3.6. the Towers of Hanoï {img {@ src="https://upload.wikimedia.org/wikipedia/commons/thumb/0/07/Tower_of_Hanoi.jpeg/260px-Tower_of_Hanoi.jpeg" width="100%"}} _p The last example illustrates a double recursive process {pre '{def MOVE {lambda {:n :from :to :via} {{{ISNIL :n} {PAIR {lambda {:n :from :to :via} } {lambda {:n :from :to :via} {MOVE {PRED :n} :from :via :to} {br}move disc from :from to :to {MOVE {PRED :n} :via :to :from} }}} :n :from :to :via}}} -> {def MOVE {lambda {:n :from :to :via} {{{ISNIL :n} {PAIR {lambda {:n :from :to :via} } {lambda {:n :from :to :via} {MOVE {PRED :n} :from :via :to} {br}move disc from :from to :to {MOVE {PRED :n} :via :to :from} }}} :n :from :to :via}}} '{MOVE FOUR 1 2 3} -> move disc from 1 to 3 move disc from 1 to 2 move disc from 3 to 2 move disc from 1 to 3 move disc from 2 to 1 move disc from 2 to 3 move disc from 1 to 3 move disc from 1 to 2 move disc from 3 to 2 move disc from 3 to 1 move disc from 2 to 1 move disc from 3 to 2 move disc from 1 to 3 move disc from 1 to 2 move disc from 3 to 2 } _p The row {code '{br}move disc from :from to :to} demonstrates how easy it is to mix text and variables. In '{lambda talk} strings don't need to be protected by quotes. _p At this point '{lambda talk} is still reduced to a couple of special forms {code [ lambda, def ]} working on words and the dictionary contains {pre {WRAP} [ HI, AFFIRMATION, PAIR, LEFT, RIGHT, REPUBLIC, NIL, ISNIL, LIST.DISPLAY, ZERO, SUCC, CHURCH, DECIM, ONE, TWO, THREE, FOUR, FIVE, ADD, MULT, POWER, PRED.PAIR, PRED, SUBTRACT, FAC, Y, ALMOST_FAC, YFAC, DIV.r, DIV, MOVE ] } _p Theoretically any computation can be done, for instance {b '{CHURCH {FAC 50}}} would display 30414093201713378043612608166064768844377641568960 512000000000000 pipes. But if computing the factorial of 5 is relatively fast, computing the factorial of 50 would still be too long! Probably thousands years. _p It's time to enter the real life! } _h2 4. '{lambda web} {center {img {@ src="data/brussels/browsers_icons.jpg" height="90"}} {img {@ src="data/brussels/braces.png" height="90" style="background:#888"}} {br}{i tel un nain sur les épaules de géants} } {div {COLUMNS} _p In fact - and fortunately - '{lambda talk} can take benefit of the powerful functions of web browsers - JAVASCRIPT, HTML/CSS, DOM, SVG, ... - allowing to avoid re-inventing the wheel and to build much more efficient code. The dictionary contains more than 200 built-in primitives {pre {WRAP} DICTionary: (203) [ debug, browser_cache, lib, eval, apply, < , >, < =, >=, =, not, or, and, +, -, *, /, %, abs, acos, asin, atan, ceil, cos, exp, floor, pow, log, random, round, sin, sqrt, tan, min, max, PI, E, date, serie, map, reduce, equal?, empty?, chars, charAt, substring, length, first, rest, last, nth, replace, cons, cons?, car, cdr, cons.disp, list.new, list, list.disp, list.null?, list.length, list.reverse, list.first, list.butfirst, list.last, list.butlast, array.new, array, array.disp, array.array?, array.null?, array.length, array.in?, array.get, array.item, array.first, array.last, array.rest, array.slice, array.concat, array.set!, array.addlast!, array.push!, array.sublast!, array.pop!, array.addfirst!, array.unshift!, array.subfirst!, array.shift!, array.reverse!, array.sort!, @, div, span, a, ul, ol, li, dl, dt, dd, table, tr, td, h1, h2, h3, h4, h5, h6, p, b, i, u, center, hr, blockquote, sup, sub, del, code, img, pre, textarea, canvas, audio, video, source, select, option, object, svg, line, rect, circle, ellipse, polygon, polyline, path, text, g, mpath, use, textPath, pattern, image, clipPath, defs, animate, set, animateMotion, animateTransform, br, input, iframe, mailto, back, hide, long_mult, turtle, drag, note, note_start, note_end, show, lightbox, minibox, editable, forum, lisp ] } _p and the set of special forms is extended to 9 {pre [ lambda def if let macro script style require quote|' ] } _p For instance using numbers and their associate operators - [+, -, *, /, ..., =, <, >, ...] - proposed by Javascript and adding a control structure {b '{if bool then one else two}} giving for free the lazy evaluation laboriously coded in the previous recursive algorithms, we can write readable and more efficient codes. {pre '{def fac {lambda {:n} {if {= :n 0} then 1 else {* :n {fac {- :n 1}}}}}} -> {def fac {lambda {:n} {if {= :n 0} then 1 else {* :n {fac {- :n 1}}}}}} '{fac 5} -> {fac 5} '{fac 50} -> {fac 50} // limited to 15 digits } _p Calling an appropriate JS library stored in some wiki page, {b lib_BN}, we can compensate the limitations of JS numbers - 15 digits max - and build a '{lambda talk} code computing the {b 65} digits of {b 50!} {require lib_BI lib_BN lib_mathLT} {pre '{def fact {lambda {:n} {if {< :n 2} then {BN.new 1} else {BN.* :n {fact {- :n 1}}}}}} -> {def fact {lambda {:n} {if {< :n 2} then {BN.new 1} else {BN.* :n {fact {- :n 1}}}}}} '{fact 50} -> 30414093201713378043612608166064768844377641568960512000000000000 } _p And we can simply call the predefined JS function {b BN.fac} to quickly compute the {b 1120} digits of big numbers, say {b 500!} {pre {@ style="word-wrap: break-word; white-space:pre-wrap;"} '{BN.fac 500} -> 1220136825991110068701238785423046926253574342803192842192413588385845373153881997605496447502203281863013616477148203584163378722078177200480785205159329285477907571939330603772960859086270429174547882424912726344305670173270769461062802310452644218878789465754777149863494367781037644274033827365397471386477878495438489595537537990423241061271326984327745715546309977202781014561081188373709531016356324432987029563896628911658974769572087926928871281780070265174507768410719624390394322536422605234945850129918571501248706961568141625359056693423813008856249246891564126775654481886506593847951775360894005745238940335798476363944905313062323749066445048824665075946735862074637925184200459369692981022263971952597190945217823331756934581508552332820762820023402626907898342451712006207714640979456116127629145951237229913340169552363850942885592018727433795173014586357570828355780158735432768888680120399882384702151467605445407663535984174430480128938313896881639487469658817504506926365338175055478128640000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 } _p Here are some other applications using external JS libraries stored in wiki pages: an embedded spreadsheet understanding '{lambda talk} expressions, Academic paper, in ACM US format, generated directly from the browser, 3D-graphics, Turtle graphics, Mandelbrot set, Ray-tracing and functions to write maths formulas. {center {show {@ src="data/brussels/spreadsheet_shot.jpg" height="140" width="1000" title="An integrated spreadsheet using lambda talk expressions." style="border:1px solid #ccc"}} {show {@ src="data/brussels/PDF_paper.jpg" height="140" width="1000" title="Academic paper, ACM US format, generated directly from the browser." style="border:1px solid #ccc"}} {show {@ src="data/brussels/pforms_coons.jpg" height="120" width="600" title="Coons patches built on 6 cubic spline curves with embedded regular polygons" style="border:1px solid #ccc"}} {show {@ src="data/brussels/turtle_20161105.jpg" height="120" width="600" title="Turtle graphics with Lindenmeier, L-system" style="border:1px solid #ccc"}} {show {@ src="data/brussels/mandel_20160104.jpg" height="120" width="600" title="Fractals, the MandelBrot set" style="border:1px solid #ccc"}} {show {@ src="data/brussels/d1.jpg" height="120" width="550" title="Integrated Ray-tracing" style="border:1px solid #ccc"}} {div {@ style="font:italic 1.9em georgia;"} i{del h}{QUOTIENT 40 ∂ψ ∂t} (x,t) = {PAREN 3 (}mc{sup 2}α{sub 0} - i{del h}c {SIGMA 40 j=1 3} α{sub j}{QUOTIENT 40 ∂ ∂x{sub j}} {PAREN 3 )} ψ(x,t) } } _p The most important thing to understand is that there is not any magic behind the curtain. Everything can always been reducible to a sequence of replacements on words layed on an infinite stripe. _p For instance we have demonstrated that - using the terrific Y-combinator - the code of the {b FAC} function could be reduced to a pure λ-calculus expression made of words, abstractions and applications. Replacing the word {b lambda} by the character "{b λ}", forgetting prefixing functions arguments with {b :} - in fact useless here - we can display the code as a sequence of characters and curly braces calling the two operations, abstraction & application, working on a dictionary initially empty. {pre {@ style="word-wrap: break-word; white-space:pre-wrap;"} °° {{λ {n} {{λ {g n} {g g n}} {λ {g n} {{{{λ {n} {n {λ {x} {λ {z} {z {λ {x y} y}}}} {λ {z} {z {λ {x y} x}}}}} n} {{λ {x y z} {z x y}} {λ {g n} {λ {f x} {f x}}} {λ {g n} {{λ {n m f x} {n {m f} x}} n {g g {{λ {n} {{λ {z} {z {λ {x y} x}}} {{n {λ {p} {{λ {x y z} {z x y}} {{λ {z} {z {λ {x y} y}}} p} {{λ {n f x} {f {{n f} x}}} {{λ {z} {z {λ {x y} y}}} p}}}}} {{λ {x y z} {z x y}} {λ {f x} x} {λ {f x} x}}}}} n}}}}}} g n }} n}} {λ {f x} {f {f {f {f {f x}}}}}}} °° } _p We are very close to the process translated in the 1930s by a student of {b Church}, {b Alan Turing}, into the shape of an hypothetic machine made of a window and an infinite stripe. {img {@ src="data/brussels/turing_machine.png" width="100%"}} _p It may be interesting to know that in '{lambda talk} replacements of expressions between curly braces are made through a {b window} built on a single {b regular expression} {pre {@ style="font:normal 1.2em courier; text-align:center;"} {quote /\{([^\s{}]*)(?:[\s]*)([^{}]*)\}/g }} _p following the syntax of a language created by {b Stephen Cole Kleene}, another student of {b Church}. These regular expressions are also at the heart of lambdas which are noting but machines to replace words by other words. _p Alonzo Church and his students were working at Princeton in the 1930s, with nothing other tool but paper, a pencil and a rubber. It must have been exciting to live in Princeton in those years! Provided having in the head, like them, the power of computers that did not exist yet. } _h2 conclusion {img {@ src="http://epsilonwiki.free.fr/epsilonwiki/data/hommes.jpg" width="100%"}} {div {COLUMNS} _p As a dwarf standing on their shoulders, '{lambda talk} takes benefit from the extraordinary power of modern web browsers. It does not re-invent the wheel and simply adds a {b coherent and unique language on existing tools} - HTML/CSS, the DOM, Javascript, PHP, ... _p The '{lambda way} project adds on browsers a thin overlay, '{lambda tank}, proposing a small "Interactive Development Environment" - {input {@ type="button" value="open frame editor" onclick="LAMBDATANK.toggle_display('frame_editor')"}} - without any external dependencies and thereby {b easy to download and install}, 50kb zipped, on any web account provider running PHP. _p From any web browser, on any system, complex and dynamic web pages can be created, enriched, structured and tested in real time on the web. And it's free! _p {b It's exactly how the current wiki page was created}. _p {i alain marty 01/01/2018} _p {img {@ src="http://epsilonwiki.free.fr/epsilonwiki/data/lepetitnicolas.jpg" width="150"}} } {blockquote _p La suite se voit dans le [[workshop|../workshop]] du projet '{lambda way} où vous trouverez des introductions plus directes au langage '{lambda talk}, notamment [[introduction]], [[primal]], [[rosetta]], [[lambdapub]], [[oxford_slides]] ainsi que de nombreux exemples d'application aux maths et au web design ou à l'enseignement, [[teaching]]. } {{hide} {def LAFABRIQUE {img {@ src="data/brussels/nef.jpg" width="100%"}} {div {@ style="font:bold italic 3.8em courier new; text-align:center; color:#fff; text-shadow:0 0 8px #000; margin-top:-1.2em;"}'{lambda {www} factory}} } {def WRAP {@ style="word-wrap: break-word; white-space:pre-wrap;"}} {def COLUMNS {let { {:count 2} } {@ style="-webkit-column-count::count; -moz-column-count::count; column-count::count;"}}} } {style #frame_view { width:100%; } h1, h2, h3 { border-top:1px solid #ccc; } pre { word-wrap: break-word; white-space:pre-wrap;} }