{lambda speech} lambdaspeech :: fabric

Jul 7, 2018 - approach based on Regular Expressions [11] introduced in the following section. ... lambdas are first class, essentially they can be called as arguments, returned as ... lambdas are pure functions, like mathematical functions the list of arguments .... A known solution is to split the recursive function into some ...
748KB taille 0 téléchargements 309 vues
lambdaspeech :: fabric {lambda speech} Alain Marty Engineer Architect Villeneuve de la Raho, France

[email protected]

ABSTRACT Wikis are everywhere. In a typical wiki, text is written using simplified syntaxes which are not designed for creating rich and highly structured documents naturally intermixing text and code. In this paper we introduce {lambda speech}, a small functional language, dialect of the λ-calculus, working in a wiki engine staying as a light overlay on any modern web browsers.

KEYWORDS • Information systems~Wikis • Theory of computation~Regular languages • Theory of computation~Lambda calculus • Software and its engineering~Functional languages • Software and its engineering~Extensible Markup Language

INTRODUCTION « There are hundred of wiki engines and hundred of languages! Why yet another wiki and another language nobody will ever want to use? » A wiki[1] is a web application which allows collaborative modi‡cation, extension, or deletion of its content and structure. Following

the first wiki created in 1995 by Ward Cunningham[2] hundred of wikis have moved us from simple consumers to creators of shared informations. The best known of wikis is Wikipedia, full of rich documented pages written by authors supposed to be neither web designers nor coders. Wikis come generally with rather rudimentary and heterogeneous syntaxes to enter, enrich and structure texts. At the lowest level documents are created using HTML & CSS syntaxes. But writing HTML/CSS code being rather complex and at least tiresome, intermediate syntaxes, for instance Markdown syntax[3], have been created to make things a little bit easier. Everything works well but the code quickly becomes rather obfuscated, difficult to write, read, edit and maintain. In fact, the Markdown syntax is not intended for writing rich documents. Works have been done to build enhanced syntaxes, true languages, in order to unify authoring, styling and coding, for instance CURL[4], LML[5], Scribble[6], SXML[7], LAML[8], Pollen[9] ... But these tools are definitively devoted to coders, not to web designers and even less to authors, making difficult - if not impossible - a true collaborative work. As a very elementary illustration, using these tools, sequences of words must always been "protected" as strings between quotes - say {print "Hello World"} [20] - and it's definitely unacceptable in the context of a wiki, as it is in a text or spreadsheet editor. Hence {lambda speech}. {lambda speech} is a small language working in a wiki engine staying as a light overlay and free of any dependances on any modern web browsers. The wiki engine is nothing but a very rudimentary standard wiki without any original contribution. Its best quality is to be easy to install on any host providers - they generally run PHP - and easy to use: you write text, see the result in real time and save/publish. In the following we forget the wiki and show the "making of" {lambda speech}, built on a minimal set of rules. Imagine a machine which understands this question: replace "fruit" and "unknown"        in "The color of fruits is unknwon."        by "apple" and "green" and returns The color of apples is green. {lambda speech} is such a replacement machine waiting for an expression formulated in a slightly different syntax

{{lambda {fruit unknown}             The color of fruits is unknown.}             apple green} and progressively evaluated to words .  {{lambda {fruit unknown} The color of fruits is unknown.} apple green}  ­> {{lambda {unknown} The color of apples is unknown.} green}  ­> {{lambda {} The color of apples is green.} }  ­> The color of apples is green. It's nothing but text substitutions in a sequence of words. Let's try expressions nesting lambdas {{lambda {z} {z {lambda {x y} x}} {{lambda {x y z} {z x y}} ♥ ♠}}} ­> ♥  {{lambda {z} {z {lambda {x y} y}} {{lambda {x y z} {z x y}} ♥ ♠}}} ­> ♠ These expressions work on a couple of words, [ ♥ ♠ ], and respectively return the first and the second. It's rather easy to follow substitutions in the first expression leading to ♥ .  {{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} ♥ ♠}  ­> ♥ We can go further building much more complex replacements using deeply nested lambdas {{lambda {f n} {f f n}} {lambda {f t} {{{{lambda {n} {n {lambda {x} {lambda {z} {z {lambda  {x y} y}}}} {lambda {z} {z {lambda {x y} x}}}}} t} {{lambda {x y z} {z x y}} {lambda {f  t}} {lambda {f t} {{lambda {z} {z {lambda {x y} x}}} t} {f f {{lambda {z} {z {lambda {x y}  y}}} t}}}}} f t}} {{lambda {x y z} {z x y}} apple {{lambda {x y z} {z x y}} banana  {{lambda {x y z} {z x y}} lemon {{lambda {x y z} {z x y}} orange {lambda {f x} x}}}}}}    ­> apple banana lemon orange Following the cascade of replacements in such a convoluted expression is far to be obvious! The amazing fact is that, as we will discover in the following section, this expression made of words, lambdas and curly braces, hides two data structures, a pair, a list and a control structure, the recursion, which are the Maxwell's Equations of functional computing. In fact we have in hands anything we need to reverse, append and sort lists, count their elements, build numbers and their related operators, compute the factorial of a number, play with the Towers of Hanoï, and so on. Theoretically ad libitum.

1. THE FOUNDATIONS {lambda speech} is freely inspired from the λ-calculus language created in the 1930s by Alonzo Church [10]. {lambda speech} is a dialect of λ-calculus. At the lowest level expressions are made of words, abstractions & applications recursively evaluated to words: ­ word        is [^\s{}]*  ­ application is (expression1 expression2)  ­ abstraction is (lambda (words) expression) More precisely • a word is a group of any characters except spaces and curly braces {}, and stands for itself, ie is its own value, • an application determines if expression1 is bound to a function then evaluates expression2 into words2, applies that function to words2 and returns other words, • an abstraction is evaluated into a word bound to an anonymous function selecting words (arguments) in expression (body) to be replaced by some future given words (values). The evaluation stops when the code is reduced to words without any curly braces. These words are sent to the browser's engine for anymore evaluations - HTML/CSS/SVG,... - and the final display. That's all!

For convenience we will add a second special form, definition, with which users can create constants and give a name to anonymous functions • a definition is a special form written {def word expression}, which evaluates expression - the body -, binds word - the name - to a function returning body and returns the name. Definitions are evaluated after lambdas and before applications. {lambda speech} is not implemented on a standard AST approach, evaluate( build_tree( tokenize( code ))), but on an original approach based on Regular Expressions [11] introduced in the following section.

2. IMPLEMENTATION The heart of {lambda speech} is an Immeditely Invoked Function Expression (IIFE). This is its minimal state var SPEECH = (function() {    return {       DICT: {}                      // the dictionary is initially empty      evaluate:function(s) { ... }  // a single public function    }  })();

1.1. the main function Each key entry in the wiki - or in a simple HTML interface - calls the function SPEECH.evaluate( code ) var evaluate = function(s) {      var bal = balance(s);      if (bal.left === bal.right) {        s = preprocessing(s);        s = eval_special_forms(s);        s = eval_forms(s);        s = postprocessing(s);      }      return {val:s, bal:bal};  }; var eval_special_forms = function(s, flag) {      while (s !== (s = form_replace(s, "quote",  eval_quote)));     // to be added later       while (s !== (s = form_replace(s, "let",    eval_let)));       // to be added later      while (s !== (s = form_replace(s, "lambda", eval_lambda)));      while (s !== (s = form_replace(s, "def",    eval_def, flag))); // to be added later      while (s !== (s = form_replace(s, "if",     eval_if)));        // to be added later      return s;  }; In the following we will forget any special form except lambdas.

1.2. forms evaluation Simple forms are nested expressions evaluated after special forms and from inside out. The process is built on a single line of Javascript running a single regular expression over and over the input string, replacing {first rest} terminal expressions - the leaves until there are no more changes [12]. var eval_forms = function(s) {      var regexp = /\{([^\s{}]*)(?:[\s]*)([^{}]*)\}/g;      while (s !== (s = s.replace( regexp, eval_form ))) ;      return s;  };    var eval_form = function() {      var first = arguments[1] || "", rest = arguments[2] || "";      return DICT.hasOwnProperty(first)        ? DICT[first].apply(null, [rest]) : "[" + first + " " + rest + "]";  };

The fact that it is repeated application of the same transformation makes the process effective. Repeated application of Regular Expressions can perform Turing Complete computations [13]. This works because the "needed state" is in the partially evaluated text itself.

1.3. lambdas' evaluation Lambdas are the heart of {lambda speech} and have the following properties • lambdas are first class, essentially they can be called as arguments, returned as values and created at run-time, • lambdas brings some laziness in an applicative order evaluation process, • lambdas can be nested, • lambdas accept vals' number < args' number, functions accept partial calls, memorizing the given values and returning a new function waiting for the rest, • lambdas accept vals' number > args' number, extra values are simply gathered in the last argument, • lambdas are pure functions, like mathematical functions the list of arguments determines the local working environment, there is no access to any external variables, no closure, no free variables, no side effects, • lambdas abstract from the main code long string a set of short sub-strings in which anymore evaluations can be quickly performed. The code string has been transformed into a tree of strings before the evaluation starts. Everything is done in the eval_lambda() function: var eval_lambda = function(s) {       s = eval_special_forms(s);  // recursive call      var index = s.indexOf(")"),        argStr = supertrim(s.substring(1, index)),        args = argStr === "" ? [] : argStr.split(" "),        body = s.substring(index + 2).trim(),        name = "_LAMB_" + LAMB_num++,        reg_args = [];      for (var i = 0; i  AFFIRMATION    {AFFIRMATION apple green} ­> The color of apples is green.  {AFFIRMATION banana yellow} ­> The color of bananas is yellow.

4. DATA & CONTROL STRUCTURES In order to understand how the long and unreadable expression given in the introductive section can be composed, we are going to build it from a set of smaller compositions of lambdas. First we define 3 functions, [PAIR, LEFT, RIGHT] {def PAIR {lambda {:x :y :z} {:z :x :y}}} ­> PAIR  {def LEFT {lambda {:z} {:z {lambda {:x :y} :x}}}} ­> LEFT  {def RIGHT {lambda {:z} {:z {lambda {:x :y} :y}}}} ­> RIGHT We have just defined a fundamental data structure. Something close to the [cons, car cdr] construction well known in the LISP/SCHEME world [14][15]. Thanks to this data structure we can aggregate two words with PAIR and access each of them with LEFT and RIGHT {def ♥♠ {PAIR ♥ ♠}} ­> ♥♠    {LEFT {♥♠}} ­> ♥   {RIGHT {♥♠}} ­> ♠ We define two associated functions, [NIL, NIL?], where NIL? is a predicate function returning LEFT if applied on NIL or RIGHT if applied on a pair. {def NIL? {lambda {:n} {:n {lambda {:x} RIGHT} LEFT}}} ­> NIL?  {def NIL {lambda {:f :x} :x}} ­> NIL      {NIL? NIL} ­> LEFT   {NIL? {♥♠}} ­> RIGHT We can compose PAIRs to build lists terminating with NIL {def FRUITS {PAIR apple {PAIR banana {PAIR lemon {PAIR orange NIL}}}}} ­> FRUITS and access each of their elements with LEFT and RIGHT {LEFT {FRUITS}} ­> apple   {LEFT {RIGHT {FRUITS}}} ­> banana  {LEFT {RIGHT {RIGHT {FRUITS}}}} ­> lemon  {LEFT {RIGHT {RIGHT {RIGHT {FRUITS}}}}} ­> orange  {RIGHT {RIGHT {RIGHT {RIGHT {FRUITS}}}}} ­> NIL This sequence of expressions enlights a "pattern" leading to a recursive function displaying the list

{def LIST.DISP {lambda {:l}    {{{NIL? :l}     {PAIR {lambda {:l} }           {lambda {:l} {LEFT :l} {LIST.DISP {RIGHT :l}} } }} :l}}} ­> LIST.DISP    {LIST.DISP {FRUITS}} ­> apple banana lemon orange Let's trace the definition and the evaluation of {LIST.DISP {FRUITS}}. We rewrite this definition using 2 helper functions, [one, two] in order to enlight the process of delaying and forcing evaluation: • first delaying one & two with lambdas • then forcing one OR two depending on bool {def one {lambda {:l} }} ­> one  {def two {lambda {:l} {LEFT :l} {LIST.DISP {RIGHT :l}} }} ­> two  {def LIST.DISP {lambda {:l} {{{NIL? :l} {PAIR one two}} :l} }} ­> LIST.DISP So {LIST.DISP {FRUITS}}  ­> {{lambda {:l} {{{NIL? :l} {PAIR one two}} :l}} {FRUITS}}  ­> {{{NIL? {FRUITS}} {PAIR one two}} {FRUITS}}  ­> {{RIGHT {PAIR one two}} {FRUITS}}  ­> {two {FRUITS}}  ­> {{lambda {:l} {LEFT :l} {LIST.DISP {RIGHT :l}}} {FRUITS}}  ­> {LEFT {FRUITS}} {LIST.DISP {RIGHT {FRUITS}}}  ­> apple {LIST.DISP {RIGHT {FRUITS}}}  and so on, recursively  ­> apple banana {LIST.DISP {RIGHT {RIGHT {FRUITS}}}}  ­> apple banana lemon {LIST.DISP {RIGHT {RIGHT {RIGHT {FRUITS}}}}}  ­> apple banana lemon orange {LIST.DISP {RIGHT {RIGHT {RIGHT {RIGHT {FRUITS}}}}}}  ­> apple banana lemon orange {LIST.DISP NIL}  until the end case  ­> apple banana lemon orange {{lambda {:l} {{{NIL? :l} {PAIR one two}} :l}} NIL}  ­> apple banana lemon orange {{{NIL? NIL} {PAIR one two}} NIL}  ­> apple banana lemon orange {{LEFT {PAIR one two}} NIL}  ­> apple banana lemon orange {one NIL}  ­> apple banana lemon orange {{lambda {:l} } NIL}  ­> apple banana lemon orange So, the obfuscated expression given in the introductive section and the {LIST.DISP} user defined recursive function lead to the same result. We still have to demonstrate that they are equivalent. The problem is that a recursive function calls its name in its body and so must be named. We have to eliminate names - we have to forget the second special form def - to get a chance to find an expression exclusively made of words and lambdas. A known solution is to split the recursive function into some Y-combinator and an ALMOST recursive function which doesn't call its name in its body {def Y {lambda {:f :n} {:f :f :n}}} ­> Y    {def ALMOST {lambda {:f :l}   {{{NIL? :l}     {PAIR {lambda {:f :l} }           {lambda {:f :l} {LEFT :l} {:f :f {RIGHT :l}} } }} :f :l}}} ­> ALMOST    {Y ALMOST {FRUITS}} ­> apple banana lemon orange Finally, replacing in {Y ALMOST {FRUITS}} all user defined names, PAIR, LEFT, RIGHT, NIL, NIL?, Y, ALMOST, FRUITS, by their lambda definitions, we get an expression exclusively made of words and lambdas, in a pure λ-calculus style {{lambda {:f :n} {:f :f :n}} {lambda {:f :t} {{{{lambda {:n} {:n {lambda {:x} {lambda {:z}  {:z {lambda {:x :y} :y}}}} {lambda {:z} {:z {lambda {:x :y} :x}}}}} :t} {{lambda {:x :y  :z} {:z :x :y}} {lambda {:f :t}} {lambda {:f :t} {{lambda {:z} {:z {lambda {:x :y} :x}}}  :t} {:f :f {{lambda {:z} {:z {lambda {:x :y} :y}}} :t}}}}} :f :t}} {{lambda {:x :y :z} {:z  :x :y}} apple {{lambda {:x :y :z} {:z :x :y}} banana {{lambda {:x :y :z} {:z :x :y}} lemon  {{lambda {:x :y :z} {:z :x :y}} orange {lambda {:f :x} :x}}}}}}  ­> apple banana lemon orange

To sum up, with nothing but 3 rules, words, abstractions, applications, we have built two data structures, pairs & lists, and a control structure, recursion. Let's give some more examples of application. For instance we can reverse and append lists {def LIST.REVERSE   {def LIST.REVERSE.rec {lambda {:a :b}     {{{NIL? :a}     {PAIR {lambda {:a :b} :b}           {lambda {:a :b} {LIST.REVERSE.rec {RIGHT :a} {PAIR {LEFT :a} :b}}} }} :a :b}}}   {lambda {:a} {LIST.REVERSE.rec :a NIL}}} ­> LIST.REVERSE     {def LIST.APPEND {lambda {:a :b} {LIST.REVERSE.rec {LIST.REVERSE :a} :b}}} ­> LIST.APPEND    {LIST.DISP {LIST.REVERSE {FRUITS}}} ­> orange lemon banana apple     {LIST.DISP {LIST.APPEND {FRUITS} {LIST.REVERSE {FRUITS}}}}  ­> apple banana lemon orange orange lemon banana apple We can compute the length of a LIST provided we accept to use a primitive numeral unary notation, ie 1 = |, 2 = | |, 3 = | | |, 4 = | | | | {def LIST.LENGTH {lambda {:l}    {{{NIL? :l}     {PAIR {lambda {:l} }           {lambda {:l} | {LIST.LENGTH {RIGHT :l}}} }} :l}}} ­> LIST.LENGTH    {LIST.LENGTH {FRUITS}} ­> | | | |   // 4 Obviously it's time to introduce numbers!

5. NUMBERS At this point we are supposed not to use numbers, operators and Math functions coming with Javascript. We have to build them exclusively from words and lambdas. Alonzo CHURCH defined a number N as a function iterating N times the application of a function f on a variable x. We will choose another way and define natural numbers as lists of any word, for instance a pipe | N = {PAIR | {PAIR | ... n times ... NIL}} With such a definition finding the SUCCessor and the PREDecessor of any number is straightforward {def SUCC {lambda {:n} {PAIR | :n}}} ­> SUCC  {def PRED {lambda {:n} {{NIL? :n} {PAIR :n {RIGHT :n}} }}} ­> PRED We begin to build the set of natural numbers {def ZERO NIL}            ­> ZERO   & {LIST.DISP {ZERO}}  ­>   {def ONE {SUCC {ZERO}}}   ­> ONE    & {LIST.DISP {ONE}}   ­> |   {def TWO {SUCC {ONE}}}    ­> TWO    & {LIST.DISP {TWO}}   ­> | |   {def THREE {SUCC {TWO}}}  ­> THREE  & {LIST.DISP {THREE}} ­> | | | Note that at this point we are not theoretically allowed to build a function using Javascript numbers and operators but, for convenience, we will define a function DECIM displaying numbers in a more modern decimal one {def DECIM   {def DECIM.rec {lambda {:l :a}     {{{NIL? :l}      {PAIR {lambda {:l :a} :a }            {lambda {:l :a} {DECIM.rec {RIGHT :l} {+ :a 1}}} }} :l :a} }}   {lambda {:l} {DECIM.rec :l 0} }} ­> DECIM    {DECIM {ZERO}}         ­> 0  {DECIM {PRED {TWO}}}   ­> 1  {DECIM {TWO}}          ­> 2  {DECIM {SUCC {TWO}}}   ­> 3  {DECIM {PRED {ZERO}}}  ­> 0  // fixed to 0

We define some arithmetic operators, ADD, SUB, MUL, POW {def ADD {lambda {:a :b}    {{{NIL? :b}     {PAIR {lambda {:a :b} :a}           {lambda {:a :b} {ADD {SUCC :a} {PRED :b}}} }} :a :b}}} ­> ADD    {def SUB {lambda {:a :b}    {{{NIL? :b}     {PAIR {lambda {:a :b} :a}           {lambda {:a :b} {SUB {PRED :a} {PRED :b}}} }} :a :b}}} ­> SUB    {def MUL   {def MUL.rec {lambda {:a :b :c}     {{{NIL? :b}      {PAIR {lambda {:a :b :c} :a}            {lambda {:a :b :c} {MUL.rec {ADD :a :c} {PRED :b} :c}} }} :a :b :c}}}   {lambda {:a :b} {MUL.rec :a {PRED :b} :a}}} ­> MUL    {def POW   {def POW.rec {lambda {:a :b}     {{{NIL? :b}      {PAIR {lambda {:a :b} :a}            {lambda {:a :b} {POW.rec {ADD :a :a} {PRED :b}}} }} :a :b}}}   {lambda {:a :b} {POW.rec :a {PRED :b}}}} ­> POW    {def FOUR {ADD {TWO} {TWO}}}     ­> FOUR  {def FIVE {ADD {TWO} {THREE}}}   ­> FIVE  {def SIX  {MUL {TWO} {THREE}}}   ­> SIX  {def SEVEN {ADD {THREE} {FOUR}}} ­> SEVEN  {def EIGHT {MUL {TWO} {THREE}}}  ­> EIGHT  {def NINE {MUL {THREE} {THREE}}} ­> NINE  {def TEN {MUL {TWO} {FIVE}}}     ­> TEN To define the DIV, MOD operators we use the Euclid algorithm a = b*q+r {def EUCLID   {def EUCLID.r {lambda {:a :b :q :r}     {{{NIL? {SUB {MUL :b :q} :a}}      {PAIR {lambda {:a :b :q :r} {EUCLID.r :a :b {SUCC :q} {SUB :a {MUL :b :q}}}}            {lambda {:a :b :q :r} {PAIR {PRED :q} :r} } }} :a :b :q :r}}}   {lambda {:a :b}    {EUCLID.r :a :b {ZERO} :b}}} ­> EUCLID    {def DIV {lambda {:a :b} {LEFT {EUCLID :a :b}}}}  ­> DIV  {def MOD {lambda {:a :b} {RIGHT {EUCLID :a :b}}}} ­> MOD    {DECIM {DIV {FIVE} {TWO}}} ­> 2  {DECIM {MOD {FIVE} {TWO}}} ­> 1  {DECIM {DIV {SIX} {TWO}}}  ­> 3  {DECIM {MOD {SIX} {TWO}}}  ­> 0 Computing the factorial function n! = 1*2*3* ... *n is straightforward {def FAC {lambda {:n}    {{{NIL? :n}     {PAIR {lambda {:n} {ONE}}           {lambda {:n} {MUL :n {FAC {PRED :n}}}} }} :n}}} ­> FAC    {DECIM {FAC {SIX}}} ­> 720 Note that the implementation of numbers as lists and operators as recursive processes has a severe limit, long lists may exceed the stack capacity, as it is the case for values beyond SEVEN.

As a last example we define functions MAP and SERIE {def MAP   {def MAP.r {lambda {:f :l :acc}     {{{NIL? :l}      {PAIR {lambda {:f :l :acc} :acc}            {lambda {:f :l :acc}                        {MAP.r :f {RIGHT :l} {PAIR {:f {LEFT :l}} :acc}}} }} :f :l :acc}}}   {lambda {:f :l} {MAP.r :f :l NIL}}} ­> MAP    {def SERIE   {def SERIE.r {lambda {:a :b :l}     {{{NIL? {SUB :b :a}}      {PAIR {lambda {:a :b :l} {PAIR :b :l}}            {lambda {:a :b :l} {SERIE.r {SUCC :a} :b {PAIR :a :l}}} }} :a :b :l}}}   {lambda {:a} {SERIE.r {ONE} :a NIL}}} ­> SERIE    {LIST.DISP {MAP DECIM {SERIE {TEN}}}}  ­> 1 2 3 4 5 6 7 8 9 10  {LIST.DISP {MAP {lambda {:n} {DECIM {POW {TWO} :n}}} {SERIE {TEN}}}}   ­> 2 4 8 16 32 64 128 256 512 1024 At this point {lambda talk} is still supposed to be reduced to a couple of special forms [lambda, def] working on words, and we have added to the initially empty empty dictionary the following set of user defined functions [ HI, AFFIRMATION, PAIR, LEFT, RIGHT, ♥♠, FRUITS, NIL, NIL?, LIST.REVERSE, LIST.APPEND,  LIST.LENGTH, Y, ALMOST.REC, SUCC, PRED, ZERO, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN,  EIGHT, NINE, TEN, DECIM.rec, DECIM, ADD, SUB, MUL.rec, MUL, POW.rec, POW, EUCLID.r,  EUCLID, DIV, MOD, FAC, MAP.r, MAP, SERIE.r, SERIE ] Theoretically any computation could be done, for instance {FAC 50}. But if computing the factorial of 5 is relatively fast, computing the factorial of 50, even with a huge stack, would still be too long, probably thousands years! It's time to enter the real life!

6. A DWARF ON THE SHOULDERS OF GIANTS

{lambda speech} is not lost in an empty space and can take benefit of modern web browsers it stays on. Thanks to their powerful functionalities - HTML/CSS/SVG parsers, the DOM, Javascript - we can build superstructures making coding easier and computing efficient.

6.1. special forms In its final state {lambda speech} comes with 9 special forms, [lambda, def, if, quote|', let, macros, script, style, require] 1: {lambda {args} body}                ­> anonymous function  2: {def name expression}               ­> add a name to the dictionary  3: {quote expression} or '{expression} ­> unevaluated expression  4: {if bool then one else two}         ­> standard control structure  5: {let { {arg val} ...} body}         ­> {{lambda {args} body} vals}  6: {macro regexp to speech exp}        ­> add syntaxic sugar  7: {script JS expressions}             ­> add JS scripts to your page  8: {style CSS expressions}             ­> edit CSS rules of your page  9: {require page_1 page_2 ...}         ­> include code from other wiki pages

6.2. primitives

Currently {lambda speech} provides an extendable set of more than 150 built-in primitives STRINGS  equal?, empty?, chars, charAt, substring, length, first, rest, last, nth, replace, serie,  map, reduce,   MATHS  +, *, ­, /, %, , =, =, not, or, and, abs, acos, asin, atan, ceil, cos, exp,  floor, pow, log, random, round, sin, sqrt, tan, min, max, PI, E, date,   ARRAYS  #.new, #.disp, #.array?, #.null?, #.empty?, #.in?, #.length, #.get, #.first, #.last,  #.rest, #.slice, #.concat,   #.set!, #.addlast!, #.push!, #.sublast!, #.pop!, #.addfirst!, #.unshift!, #.subfirst!,  #.shift!, #.reverse!, #.sort!,   PAIRS, LISTS  pair, cons, pair?, nil?, left, list.first, car, right, list.rest, cdr, pair.disp,  list.new, list.disp,   HTML/CSS  @, div, span, a, ul, ol, li, dl, dt, dd, table, tr, td, h1, h2, h3, h4, h5, h6, p, b, i,  u, center, br, hr, blockquote, sup, sub, del, code, img, pre, prewrap, textarea, audio,  video, source, select, option, object, canvas,   SVG  svg, line, rect, circle, ellipse, polygon, polyline, path, text, g, mpath, use, textPath,  pattern, image, clipPath, defs, animate, set, animateMotion, animateTransform, title,  desc,   MISC  lib, input, iframe, hide, turtle, drag, localStorage.display, localStorage.removeItem,  localStorage.getItem, localStorage.clear,

6.3. applications Four examples are now given to illustrate how these "superstructures" make {lambda speech} a useful language.

6.3.1. big numbers We have seen in the previous section that computing the factorial of a number beyond 7 was an inaccessible dream with the minimal implementation based on words, applications and abstractions. Now the dream becomes reality! {def fac {lambda {:n}    {if { fac    {fac 6}   ­> 720  {fac 50}  ­> 3.0414093201713376e+64  {fac 171} ­> Infinity {fac 50} returns a float number limited to 15 digits and not the exact value. Calling an appropriate library stored in the wiki, lib_BN, we can overcome the limitations of JavaScript numbers - 15 digits maximum - and build a {lambda speech} code computing the exact value of the factorial of big numbers in a feww milliseconds. {def bigfac {lambda {:n}    {if {= {BN.compare :n 0} 0}     then 1     else {BN.* :n {bigfac {BN.­ :n 1}}}}}} ­> bigfac    {bigfac {BN.new 50}} ­> 30414093201713378043612608166064768844377641568960512000000000000     {bigfac {BN.new 500}} ­>  122013682599111006870123878542304692625357434280319284219241358838584537315388199760549644 750220328186301361647714820358416337872207817720048078520515932928547790757193933060377296 085908627042917454788242491272634430567017327076946106280231045264421887878946575477714986

349436778103764427403382736539747138647787849543848959553753799042324106127132698432774571 554630997720278101456108118837370953101635632443298702956389662891165897476957208792692887 128178007026517450776841071962439039432253642260523494585012991857150124870696156814162535 905669342381300885624924689156412677565448188650659384795177536089400574523894033579847636 394490531306232374906644504882466507594673586207463792518420045936969298102226397195259719 094521782333175693458150855233282076282002340262690789834245171200620771464097945611612762 914595123722991334016955236385094288559201872743379517301458635757082835578015873543276888 868012039988238470215146760544540766353598417443048012893831389688163948746965881750450692 636533817505547812864000000000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000

6.3.2. de casteljau algorithm A Bézier curve [16] is defined by a set of control points, [p0 p1 ... pn]. The de Casteljau’s algorithm [17] takes the control points and finds the midpoints along each line, then joins these midpoints. After that, it takes the midpoints along the newly drawn lines and finds the midpoints again, then draws a line connecting these. By doing this until we are down to only one point, we can approximate the Bézier curve. This is a schema of the de Casteljau algorithm for a cubic curve controled by 4 points [p1 p2 p3 p4] and leading to the point at t=1/2: .     [p0  p1  p2  p3]     the control polygon          [q0  q1  q2]       qi = (pi+pi+1)/2  i in [0,1,2]            [r0  r1]         ri = (qi+qi+1)/2  i in [0,1]              [s0]               s1 = (ri+ri+1)/2  i in [0] This process is recursively done on the left and right control polygons [p1 q1 r1 s1] and [s1 r2 q3 p4]. The depth of recursion is controlled either by a "flatness/smoothness" condition or by a number, the choice taken in this page. The result is a binary tree of polygon controls translated in a sequence of points, x0 y0 x1 y1 .... xp yp, expected by the SVG polyline's points:"..." attribute. The main function is {CASTEL.blossom pol n} which returns a level n binary tree of polygon controls, [[x0,y0],...,[xp,yp]]. The curve is defined in the interval [0,1]. The second {CASTEL.stretch pol t0 t1} function returns a new equivalent control polygon stretched to any other interval [t0,t1]. In order to display the curve, we define a third {array.2svg pol} function replacing the 3 characters "[",",","]" by spaces in the array expression of the control polygon and returning a sequence of SVG formated points x0 y0 x1 y1 ... xp yp. {def CASTEL.interpol {lambda {:p0 :p1 :t}    {#.new {+ {* {#.get :p0 0} {­ 1 :t}} {* {#.get :p1 0} :t}}           {+ {* {#.get :p0 1} {­ 1 :t}} {* {#.get :p1 1} :t}} } }}   ­> CASTEL.interpol    {def CASTEL.sub {lambda {:arr :acc :t}    {if { CASTEL.sub    {def CASTEL.split {lambda {:arr :acc :t :lr}    {if { CASTEL.split    {def CASTEL.stretch {lambda {:arr :t0 :t1}    {CASTEL.split     {CASTEL.split :arr {#.new} :t0 right} {#.new} :t1 left}}}  ­> CASTEL.stretch   

{def CASTEL.blossom {lambda {:arr :n}    {if { CASTEL.blossom    {def svg.points {lambda {:arr}    {replace (\[|\]|,) by space in {#.disp :arr}}}} ­> svg.points    {def svg.stroke {lambda {:c :e}   stroke=":c" stroke­width=":e" fill="transparent"}} ­> svg.stroke    {def svg.dot {lambda {:p}    {circle {@ cx="{#.first :p}" cy="{#.last :p}" r="5"    {svg.stroke #000 3}}} }} ­> svg.dot Using these functions, we can feed the SVG polyline's points:"..." attributes {svg {@ width="320" height="320"}  {polyline {@ points="{svg.points {CASTEL.blossom    {#.new {p0} {p1} {p2} {p3}} 4}}" {svg.stroke #f00 12} }}  {polyline {@ points="{svg.points {CASTEL.blossom   {#.new {p0} {p1} {p2} {p3}} 0}}" {svg.stroke #888 1} }}  {polyline {@ points="{svg.points {CASTEL.blossom {CASTEL.stretch   {#.new {p0} {p1} {p2} {p3}} 0.25 0.85} 3}}" {svg.stroke #ff0 5}}}  {polyline {@ points="{svg.points {CASTEL.blossom {CASTEL.stretch   {#.new {p0} {p1} {p2} {p3}}  ­0.1 1.1} 4}}" {svg.stroke #888 2}}}  {polyline {@ points="{svg.points {CASTEL.blossom {CASTEL.stretch   {#.new {p1} {p0} {p2} {p3}}  ­0.1 1.1} 4}}" {svg.stroke #888 2}}}  {polyline {@ points="{svg.points {CASTEL.blossom {CASTEL.stretch   {#.new {p0} {p1} {p3} {p2}}  ­0.1 1.1} 4}}" {svg.stroke #888 2}}}  {polyline {@ points="{svg.points {CASTEL.blossom {CASTEL.stretch   {#.new {p0} {p2} {p1} {p3}}  ­0.1 1.1} 4}}" {svg.stroke #888 2}}}    {svg.dot {p0}} {svg.dot {p1}} {svg.dot {p2}} {svg.dot {p3}}  } 

6.3.3. Lindenmeier L‑system With the browser's SVG functions and the {lambda speech} primitive turtle, we can define a tree using the Lindenmeier, L-system [18], and call it in a SVG container. We define a function tree depending on 5 parameters which will gather the points attribute of a polyline in a SVG container. In the first picture we play with :a :b equal to 45° and increase initial sizes to increase complexity, :k :e being constant. The red tree defines the generative pattern. The green, blue and grey trees are generated by the recursive application of this pattern at the end of the branchs for different initial sizes. In the second picture the angles :a :b are freely choosen to distord the trees. {def tree    {lambda {:e :s :k :a :b}    {if { tree {tree 25 50 {/ 2 3} 45 45}  ­> grey tree  {tree 25 100 {/ 2 3} 45 45} ­> blue tree  

{tree 5 200 {/ 2 3} 40 4}  ­> red tree  {tree 5 180 {/ 2 3} 40 10} ­> green tree 

{tree 25 150 {/ 2 3} 45 45} ­> green tree  {tree 25 200 {/ 2 3} 45 45} ­> red tree

{tree 5 180 {/ 2 3} 4 20}  ­> blue tree  {tree 5 150 {/ 2 3} 4 50}  ­> black tree

6.3.4. HTML/CSS As a last example of application, with HTML/CSS built-in primitives we have tools for building rich documents intermixing pure text and code and produce PDF files. Being a dialect of lambda calculus doesn't prevent {lambda speech} to be useful. And it's exactly how the current wiki page was created and the acmart formated PDF paper directly generated from the browser.

CONCLUSION The heart of {lambda speech} is built on a 30kb PHP file and a 60kb JS file free of any external dependancies. And more, the single function, SPEECH, contained in the JS file can be used in any other wiki. The code is small and can be read, edited and improved by any coder, it's just plain Javascript. {lambda speech} is a free software under the GNU GPL licence, and its 20kb archive is easy to download & install on any web host provider running PHP. Or can be freely tested in the website http://b2b3.free.fr/lambdaspeech. The current wiki page was built on a handfull of small {lambda speech} user functions and CSS rules. {lambda speech} keeps writing rich structured and dynamic web documents Small & Simple. First you, the author, insert your ideas, what you think, as it comes to you. Yes it's not exactly WYSIWYG, you can't select words with the mouse and click on some button [B] to boldify them. You have to write code in a text editor frame and see the result in a viewer frame. But it's in real time and you code at a minimal level, with a handful of simple textual commands closely related to standard HTML/CSS. Later you will be able to enrich the document by yourself or helped by a cute web designer or a smart coder. This collaborative creation is made possible because the author, the web designer and the coder share the same consistent code. The coder will define on demand new functions to make things easier, closer to your needs and web design requirements. And so your documents will always be sustainable, easy to edit, improve and publish, from everywhere, on every systems and every devices, free from any proprietary or/and obfuscated tools. This was the goal of {lambda speech}.

Alain Marty ‑‑2018/07/07 REFERENCES [1] The Wiki way: http://dl.acm.org/citation.cfm?id=375211  [2] Ward_Cunningham: http://ward.asia.wiki.org/view/testing­microtalk   [3] Markdown Syntax: https://help.github.com/articles/basic­writing­and­formatting­syntax/ 

[4] http://epsilonwiki.free.fr/lambdaway/?view=curl  [5] http://epsilonwiki.free.fr/lambdaway/?view=LML  [6] http://docs.racket­lang.org/scribble/  [7] http://epsilonwiki.free.fr/lambdaway/?view=SXML   [8] http://people.cs.aau.dk/~normark/laml/papers/web­programming­laml.pdf  [9] http://docs.racket­lang.org/pollen  [10] A Tutorial Introduction to the Lambda Calculus (Raul Rojas): http://www.inf.fu­ berlin.de/lehre/WS03/alpi/lambda.pdf  [11] S. C. Kleene, “Representation of events in nerve nets and finite automata”, in: C.  Shannon and J. McCarthy, (eds.) Automata Studies, Princeton University Press, NJ, 1956, 3– 41.  [12] Regular Expressions: http://blog.stevenlevithan.com/archives/reverse­recursive­ pattern  [13] Turing machines implemented in JavaScript   http://www.turing.org.uk/book/update/tmjavar.html  [14] LISP: http://www.cs.utexas.edu/~cannata/cs345/Class%20Notes/06%20Lisp.pdf  [15] SCHEME: Arold Abelson and Gerald J. Sussman. 1996. Structure and Interpretation of  Computer Programs (2nd ed.). MIT Press, Cambridge, MA, USA.  [16] Bézier curve: href="https://www.scratchapixel.com/lessons/advanced­rendering/bezier­ curve­rendering­utah­teapot"  [17] de Casteljau: https://en.wikipedia.org/wiki/De_Casteljau%27s_algorithm  [18] Lindenmeier L­system: https://en.wikipedia.org/wiki/L­system  [19] MathML google­subtracts­mathml­from­chrome: https://www.cnet.com/news/google­ subtracts­mathml­from­chrome­and­anger­multiplies/  [20] Rosetta: https://www.rosettacode.org/wiki/Hello_world/Text

l ambdaspeech v. 20180623