+
1
|
skin
|
login
|
edit
{λ way}
::
krakow
user:anonymous
{img {@ src="data/chevaux.jpg" width="100%" title="Mustangs at Las Colinas, Texas, @Robert Glen"}} {center {h1 '{lambda talk}} alain marty | engineer ECL architect DPLG | france {br} marty.alain@free.fr } {{PAGE} _h2 abstract _p The {b '{lambda way}} project is built on two engines: {ol {li {b '{lambda talk}}, a purely {b functional language} unifying writing, styling and scripting in a single and coherent notation,} {li {b '{lambda tank}}, a tiny {b wiki} easy to install as a thin overlay on top of any web browser,} } _p allowing a {b collaborative work} between authors, web designers and coders for creating and sharing {b rich documents} on the web. _h2 context _p « {i But there are hundred of wiki engines and hundred of languages! Why yet another wiki and another language nobody will ever want to use? } » Let's talk about it! _p Web browsers give everybody an easy access to a plethora of rich documents created by people mastering HTML, CSS, JS, PHP... What is less known, web browser can give everybody a small window to write HTML/CSS/JS code and so add informations to web pages. {b Wikis}{ref 1} belong to this category: « {i A wiki is a web application which allows collaborative modification, extension, or deletion of its content and structure.} » _p Writing HTML/CSS/JS code being rather complex and at least tiresome, intermediate syntaxes, for instance {b WikiText}{ref 2}, have been created to make things a bit easier. And it's exactly what people use in blogs and wikis. The best known of wikis is Wikipedia, full of rich documented pages written by people supposed not to be web designers or coders. _p Everything works well but the underlying code is a very obfuscated text, difficult to write, read, edit and maintain. In fact, the {b WikiText}{ref 2} syntax is not intended for writing rich documents. Works have been done to build enhanced syntaxes in order to unify writing, styling and coding, for instance, not to mention desktop tools like {b LaTeX}{ref 3}, {b PDF}{ref 4}, web tools like {b CURL}{ref 5}, {b LML}{ref 6}, {b Skribe}{ref 7}, {b Scribble}{ref 8}, {b SXML}{ref 9}, {b LAML}{ref 10}, {b Pollen}{ref 11} ... But these tools are definitively devoted to coders, not to web designers and even less to beginners. _p Hence the {b '{lambda way}} project ... _p In this paper we will focus on '{lambda talk}, following two steps: {ol {li using '{lambda talk}, a gentle introduction via simple examples,} {li '{lambda talk} more deeply, structure, evaluation, implementation, frequently asked questions.} } }{{PAGE} _h2 1. using '{λ talk} }{{PAGE} _h3 1.1 words _p Words are written in a code editor frame and displayed in real time in the wiki page, following some predefined styling rules. For instance: {{codeview 1} Hello brave new World {{codeview 2} Hello brave new World }} _p Sometimes styling rules have to be modified here and there. In a standard text editor, applying some bold style on a sequence of words needs two steps, 1) {b selecting} with the mouse and 2) {b applying} a command via some button {b [B]}, or via some key combination {b [^C+B]}. In '{lambda talk} the sequence {b select/apply} is based on a unique shorthand notation {code '{first rest}}, so-called {b form}, where: {ul {li 1) {code curly braces '{}} are used to {b select} a sequence of words and forms,} {li 2) {code first} is a word referencing a function belonging to a given {b dictionary} and applied to {code rest},} {li 3) {code rest} is any sequence of words and forms.} } _p This is a very simple example: {{codeview 1} Hello '{b brave new} World {{codeview 2} Hello {b brave new} World }} _p This one is more convoluted: {{codeview 1} '{b Hello {sup World, {sub is {sup there {sub anybody {sup out {sub there {sup ???}}}}}}}} {{codeview 2} {b Hello {sup World, {sub is {sup there {sub anybody {sup out {sub there {sup ??????}}}}}}}} }} _p You are in the holy world of nested prefixed expressions! In fact, the '{lambda talk} syntax is a shorthand for the standard HTML syntax. whose evaluation will lead to a sequence of words embedded in a valid HTML/CSS code sent to the browser's engine for the final display. Remember that in '{lambda talk} out of curly braces words are not evaluated. _h3 1.2 numbers _p Some words can be seen as numbers and {b '{lambda talk}} becomes a {i pocket calculator} {{codeview 1} '{+ 1 2 3} '{+ 1 {* 2 3} 4} '{sqrt 2} '{sqrt {+ {* 3 3} {* 4 4}}} {{codeview 2} {+ 1 2 3} {+ 1 {* 2 3} 4} {sqrt 2} {sqrt {+ {* 3 3} {* 4 4}}} }} _p For instance, the expression {code '{sqrt {+ {* 3 3} {* 4 4}}}} is successively replaced by {code '{sqrt {+ 9 16}}}, then by {code '{sqrt 25}} and finally by {b 5}. It's the hypotenuse of a right angle triangle {code [3,4]}. You are entering the marvelous world of mathematics. _h3 1.3 styles _p The set of HTML tags is not infinite. Thanks to CSS rules this set can be extended {i ad libitum}. For instance you {b could} apply some cyan color to words like this: {{codeview 1} '{div {@ style="color:cyan"} Hello World } {{codeview 2} {div {@ style="color:cyan"}Hello World} }} _p Or display a picture on a shadowed box like this: {{codeview 1} '{img {@ src="data/mustangs.jpg" width="98%" title="Mustangs at Las Colinas ©Robert Glen" style=" padding:5px 5px 35px 5px; border:1px solid white; background:white; box-shadow:0 0 8px black" }} {{codeview 2} {img {@ src="data/mustangs.jpg" width="98%" title="Mustangs at Las Colinas ©Robert Glen" style=" padding:5px 5px 35px 5px; border:1px solid white; background:white; box-shadow:0 0 8px black"}} }} _p Sounds familiar to any web designer, you can simply copy/paste chunks of standard HTML/CSS code. But smart web designers will say « {b {i It's a bad practice to mix structure and style!}} » Ok it's right, it's time to introduce {b constants} and {b functions}. }{{PAGE} _h3 1.4 constants _p You can put all the "ugly" {b constant} HTML/CSS stuff under a {b name} and call it later. For instance you can define the name {b cyan} and apply it later on different words: {{codeview 1} 1) define: '{def cyan span {@ style="color:cyan"}} 2) and call: '{{cyan}Hello brave new World} '{{cyan}Goodbye poor old World} {{codeview 2} {def cyan span {@ style="color:cyan"}} {{cyan}Hello brave new World} {{cyan}Goodbye poor old World} }} _p Giving a name to the messy HTML/CSS stuff defining the previous picture in a shadowed box, a friendly coder could help you to hide HTML/CSS code. Better he could externalize it in another wiki page behaving as a {b library}, extending the concept of {b CSS stylesheet} and opening a way towards more powerful capabilities. _p You can give math expressions a name, provided they are evaluable: {{codeview 1} 1) define: '{def Φ {/ {+ 1 {sqrt 5}} 2} } '{def 1*2*...*100 {* {serie 1 100}} } 2) and call: '{Φ} '{1*2*...*100} {{codeview 2} {def Φ {/ {+ 1 {sqrt 5}} 2}} {def 1*2*...*100 {* {serie 1 100}}} {Φ} {1*2*...*100} }} _h3 1.5 functions _p We have seen how to define a name as a {b constant} applying a {i given color} to some words. Defining a name waiting for future unknown colors would open an infinity of choices. We can do that using a {b function}, created with {code lambda} and named with {code def}. This is how we can replace the previous constant {code cyan} by a function {code color}: {{codeview 1} 1) define '{def color {lambda {myColor} span {@ style="color: myColor;"}}} 2) and call: '{{color cyan}Hello World} '{{color red}Hello World} {{codeview 2} {def color {lambda {myColor} span {@ style="color: myColor;"}}} {{color cyan}Hello World} {{color red}Hello World} }} _p We have seen that the expression {code '{sqrt {+ {* 3 3} {* 4 4}}}} is evaluated to 5, the hypotenuse of a right angle triangle {code [3,4]}. Using a function we can {b delay the evaluation} of {code '{sqrt {+ {* a a} {* b b}}}} containing undefined arguments {code a} and {code b} until they get their values: {{codeview 1} 1) define: '{def hypo {lambda {a b} {sqrt {+ {* a a} {* b b}}}}} 2) and call: '{hypo 3 4} '{hypo 1 1} {{codeview 2} {def hypo {lambda {a b} {sqrt {+ {* a a} {* b b}}}}} {hypo 3 4} {hypo 1 1} }} _p The name {code hypo} is nothing but an alias to {code '{lambda {a b} {sqrt {+ {* a a} {* b b}}}}} and it's rather easy to understand that {code '{hypo 3 4}} is first replaced by {code '{{lambda {a b} {sqrt {+ {* a a} {* b b}}}} 3 4}}, where {code a} and {code b} will be replaced by {code 3} and {code 4}, leading to this evaluable expression {code '{sqrt {+ {* 3 3} {* 4 4}}}}, finally replaced by {b 5}, as we have seen before. _p Mixing text and numbers is easy, {i provided you take some care}: {{codeview 1} 1) define: '{def cute_add {lambda {:a :b} {b :a+:b {sup is equal to} {u {+ :a :b}}}}} 2) and call: '{cute_add 3 4} '{cute_add 5 6} {{codeview 2} {def cute_add {lambda {:a :b} {b :a+:b {sup is equal to} {u {+ :a :b}}}}} {cute_add 3 4} {cute_add 5 6} }} _p You must know that, when a function is called, {b every} occurences of its arguments are replaced in it's {b body} by the given {b values}. In this function, prefixing by a colon the arguments, {code '{:a :b}}, prevents the {i unwanted} replacement of {code equal} by {code equ3l}. It's a good thing to {i escape} arguments everytime. _h3 1.6 fibonacci numbers _p If you like mathematics, you can define more complex functions, like {b fibonacci}{ref 12} {{codeview 1} '{def fibonacci {def fibonacci.rec {lambda {:a :b :c} {if {< :c 1} then :a else {fibonacci.rec :b {+ :a :b} {- :c 1}} }}} {lambda {:n} {fibonacci.rec 0 1 :n} }} The 75'{sup th} Fibonacci's number is: '{fibonacci 75} The 31 first Fibonacci's numbers are: '{map fibonacci {serie 0 30}} ... {{codeview 2} {def fibonacci {def fibonacci.rec {lambda {:a :b :i} {if {< :i 1} then :a else {fibonacci.rec :b {+ :a :b} {- :i 1}} }}} {lambda {:n} {fibonacci.rec 0 1 :n}}} The 75{sup th} Fibonacci's number is: {fibonacci 75} The 31 first Fibonacci's numbers are: {map fibonacci {serie 0 30}} ... }} }{{PAGE} _h3 1.7) graphics _p Let's play with Bézier curves using the {b de Casteljau} algorithm{ref 13}. Drawing can be done out of any {b canvas} or {b SVG} container, directly in the wiki page. {div {@ style="position:relative; top:0; left:0; height:200px;"} {dot 20 cyan {{def P0 {cons 100 -50}}}} {dot 20 cyan {{def P1 {cons 300 50}}}} {dot 20 cyan {{def P2 {cons 50 190}}}} {dot 20 cyan {{def P3 {cons 300 190}}}} {map {casteljau {list.new {P2} {P0} {P1} {P3}} 6 red} {serie -0.4 0.6 0.025}} {map {casteljau {list.new {P0} {P1} {P2} {P3}} 6 red} {serie -0.1 1.2 0.025}} } _p We define 2DPoints as {code pairs} and Bézier curves as {code lists} of 2D points: {pre '{def casteljau {def castel.interpol {lambda {:p0 :p1 :t} {cons {+ {* {car :p0} {- 1 :t}} {* {car :p1} :t}} {+ {* {cdr :p0} {- 1 :t}} {* {cdr :p1} :t}}} }} {def castel.sub {lambda {:l :t} {if {equal? {cdr :l} nil} then nil else {cons {castel.interpol {car :l} {car {cdr :l}} :t} {castel.sub {cdr :l} :t}} }}} {def castel.pt {lambda {:l :t} {if {equal? {cdr :l} nil} then {car :l} else {castel.pt {castel.sub :l :t} :t} }}} {lambda {:l :d :c :t} {dot :d :c {{castel.pt :l} :t}} }} '{def dot {lambda {:d :c :p} {div {@ style="position:absolute; left:{- {car :p} {/ :d 2}}px; top: {- {cdr :p} {/ :d 2}}px; width::dpx; height::dpx; border-radius::dpx; background::c; border:1px solid black"}} }} '{dot 20 cyan {{def P0 {cons 200 250}}}} '{dot 20 cyan {{def P1 {cons 500 400}}}} '{dot 20 cyan {{def P2 {cons 200 600}}}} '{dot 20 cyan {{def P3 {cons 500 600}}}} '{map {casteljau {list.new {P2} {P0} {P1} {P3}} 6 red} {serie -0.1 0.6 0.025}} '{map {casteljau {list.new {P0} {P1} {P2} {P3}} 6 red} {serie -0.2 1.2 0.025}} } {{hide} {def casteljau {def castel.interpol {lambda {:p0 :p1 :t} {cons {+ {* {car :p0} {- 1 :t}} {* {car :p1} :t}} {+ {* {cdr :p0} {- 1 :t}} {* {cdr :p1} :t}}} }} {def castel.sub {lambda {:l :t} {if {equal? {cdr :l} nil} then nil else {cons {castel.interpol {car :l} {car {cdr :l}} :t} {castel.sub {cdr :l} :t}} }}} {def castel.pt {lambda {:l :t} {if {equal? {cdr :l} nil} then {car :l} else {castel.pt {castel.sub :l :t} :t} }}} {lambda {:l :d :c :t} {dot :d :c {{castel.pt :l} :t}} }} {def dot {lambda {:d :c :p} {div {@ style="position:absolute; left:{- {car :p} {/ :d 2}}px; top: {- {cdr :p} {/ :d 2}}px; width::dpx; height::dpx; border-radius::dpx; background::c; border:1px solid black"}} }} } _h3 1.8 lambdasheet _p Following Simon Peyton-Jones{ref 14}, spreadsheets can be seen as simple functional programs. '{lambda sheet} is an {i experimental} spreadsheet which can be integrated in every wiki page. It comes with '{lambda talk} as its own integrated language. {{codeview 1} '{sheet one 8 3} {{codeview 2} {sheet one 8 3} }} _p Click on "start lambdasheet" to open the [8 rows, 3 colomns] spreadsheet, choose a cell, enter any '{lambda talk} expression then click outside to view the result. As usual cells can be linked, for instance, writing in the cell {b L3C1} {b '{+ {lc 1 1} {lc 2 1}}} will display the sum of cells {b L1C1} and {b L2C1}. _p Note that datas are stored in the browser's localStorage, allowing you to recover your datas. Feel free to test your own expressions, insert pictures, and so on. _h3 1.9 conclusion _p To conclude this section we simply mention two last applications: _ul 1) '{lambda talk} forgets the {b MathML} markup set{ref 15} which doesn't work in Chrome, and can be used to render Mathematical Symbols: {{codeview 1} °° i{del h}{quotient 30 ∂ψ ∂t}(x,t) = {br} {paren 3 (}mc{sup 2}α{sub 0} - i{del h}c {sigma 30 j=1 3} α{sub j}{quotient 30 ∂ ∂x{sub j}}{paren 3 )} ψ(x,t) °° {{codeview 2} {div {@ style="font:italic 1.0em georgia; text-align:center;"} i{del h}{quotient 30 ∂ψ ∂t}(x,t) = {br}{paren 3 (}mc{sup 2}α{sub 0} - i{del h}c {sigma 30 j=1 3} α{sub j}{quotient 30 ∂ ∂x{sub j}}{paren 3 )} ψ(x,t) } }} {{hide} {def quotient {lambda {:s :num :denom} {table {@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;"} {tr {td {@ style="border:0 solid; border-bottom:1px solid;"}:num}} {tr {td {@ style="border:0 solid;"}:denom}} }}} {def sigma {lambda {:s :one :two} {table {@ style="width::spx; display:inline-block; vertical-align:middle; text-align:center;"} {tr {td {@ style="border:0 solid;"}:two}} {tr {td {@ style="border:0 solid; font-size:2em; line-height:0.7em;"}Σ}} {tr {td {@ style="border:0 solid;"}:one}} }}} {def paren {lambda {:s :p} {span {@ style="font:normal :sem arial; vertical-align:-0.15em;"}:p}}} } _ul 2) '{lambda talk} code can be interfaced with Javascript code via a {code '{script ...}} form, allowing the exploration of intensive computing. For instance ray-tracing, curved shapes modeling, fractal and turtle graphics drawing: {center {img {@ src="http://epsilonwiki.free.fr/lambdaway_2.0/data/lambdaray_20130329/d1.jpg" height="150"}} {img {@ src="http://epsilonwiki.free.fr/alphawiki_2/data/pforms_coons.jpg" height="150"}} {img {@ src="http://epsilonwiki.free.fr/alphawiki_2/data/mandel_20160104.jpg" height="150"}} {img {@ src="data/turtle_20161105.jpg" height="150"}} } _p To sum up, '{lambda talk} takes benefit from the extraordinary power of modern web browsers, simply adding a coherent and unique notation, '{first rest}, without re-inventing the wheel, just using the existing foundations of HTML/CSS, the DOM and Javascript. It's probably why the implementation of '{lambda talk} is so easy and short, as we are going to see in the section {b 2. '{λ talk} in deep}. }{{PAGE} _h2 2. '{λ talk} in deep }{{PAGE} _p We introduce the structure and evaluation of a '{lambda talk} expression. Then we give some details about the implementation and we answer some frequently asked technical questions. _h3 2.1 structure _p '{lambda talk} is made of {b expressions}: _ul an expression is made of {b words} and/or {b forms}: _ul a word is a sequence of chars except spaces and '{} _ul a form is an expression {b '{first rest}} where: _ul30 first is a word belonging to a {b dictionary}, _ul30 rest is an expression. _ul the dictionary contains words associated to: _ul30 {b primitive functions} written in Javascript for HTML/CSS, Math, SVG, ... _ul30 {b anonymous functions} '{lambda {:word*} expressions}, _ul30 {b user definitions} '{def word expression}. _p Note that {code :word*} is for {code :word1 :word2 ...}, a sequence of colon prefixed words used as arguments to the function. _h3 2.2 evaluation _p It comes from the previous definitions that {code '{first rest}} forms are nested and are structured as flat trees. The lambdatalk's parser evaluates and translates them to a tree structured HTML/CSS code, which is sent to the browser's engine for the final evaluation and display. _p Forms are divided into two types, {b simple forms} and {b special forms}. _ul In simple forms {code first} and {code rest} are known elements. Simple forms are evaluated in a single loop, working on a unique regular expression, from the leaves to the root. _ul in special forms the {code first} term belongs to a 6 elements set, {b [{code lambda, def, if, let, quote, '}]}. Special forms are evaluated in a pre-processing phase: _ul30 {code '{lambda {:arg*} expression}} extends the dictionary with anonymous functions, binding {code :arg*} in {code expression} to future values {code val*} via such a call {code '{{lambda {:arg*} expression} val*}} _ul30 {code '{def word expression}} extends the dictionary with user constants, _ul30 {code '{let { {:arg val}* } expression}} is a syntaxic sugar for {code lambda} equivalent to {code '{{lambda {:arg*} expression} val*}} _ul30 {code '{if bool then one else two}} delays evaluation of {code bool, one, two}, _ul30 {code '{quote expression*}} prevents evaluation of a sequence of {code expressions}, _ul30 {code ''{first rest}} prevents evaluation of {code '{first rest}}. _p The dictionary contains a set of primitive functions extended with user functions. {div {@ style="font:italic 0.8em courier new; padding:0 20px;"} {lib} } _p Note: the functions listed after {code turtle} are user functions defined in this page. _h3 2.3 implementation _p Here we give some more technical details intended to highlight implementation design choices. The first of them is that lambdatalk engine doesn't use the evaluation process followed by standard interpreters which are based on an {b Abstract Syntax Tree}, something like: {pre output = walk_tree( build_tree( tokenize_string( input )))} _p In fact, lambdatalk has essentially to translate a tree structured code input into a tree structured code output, the {b HTML code}, which will be sent to the browser's engine for final evaluation and display. The couple lambdatank and lambdatalk is a light overlay, (~100kb), working on top of modern browsers, {i a dwarf on the shoulders of giants}. Lambdatalk quickly flights over words and uses Regular Expressions to catch and replace by words {b simple forms} in a loop, and {b special forms} in a pre-processing phase. This rather iconoclastic approach is considered as {i evil} by some coders, but it works fine in a wiki context. _p We give here some answers to frequently asked questions. }{{PAGE} _h4 2.3.1 How are forms evaluated? _p Special forms, [{code lambda, def, if, let, quote, '}], are evaluated before simple forms: _ul {b 1) Simple forms} '{first rest} are matched and evaluated in a loop and return words: {pre °° var eval_forms = function( str ) { while (str != (str = str.replace( leaf, eval_leaf ))) ; return str }; where: - leaf = /\{([^\s{}]*)(?:[\s]*)([^{}]*)\}/g - eval_leaf is a function applying first to rest and returning words °°} _ul {b 2) Special forms} '{symbol ...} are matched and evaluated in a similar way, according to specific patterns, and return words or forms escaped from evaluation. For instance {b lambdas}: {pre °° var eval_lambdas = function(str) { while ( str !== ( str = form_replace( str, '{lambda', eval_lambda ))) ; return str }; where: - eval_lambda is a function adding an anonymous function to the dictionary and returning its reference °°} _h4 2.3.2 Why using Regular Expressions? _p Because Regular Expressions are powerful, fast and work fine in a wiki context, allowing realtime editing (about 10ms) in most cases! This paper has been built directly in '{lambda tank}, all examples are evaluated in about 150ms on a rather recent computer. If the edition becomes too slow on older computers or some smartphones, the realtime evaluation can be switched off allowing a confortable edition. _p This is what Ward Cunningham{ref 16} wrote about that: « {i I was surprised that the technique worked so well in so many cases. I knew that regex are highly optimized and the cpus themselves optimize sequential access to memory which the regex must have at its core. [..] Yes, this has at its heart the repeated application of a text transformation. The fact that it is repeated application of the same transformation makes it exceptional. [..] Repeated application of Regular Expressions can perform Touring Complete computations. This works because the needed "state" is in the partially evaluated text itself.} » All is said! _p Finally, the regular expressions based approach allows to simply write {code '{b Hello {i brave new} World}}, without quoting words, to get {b Hello {i brave new} World}, as in this brave old HTML! As far as I know, in the similar works related in the introduction, we must write {code '{b "Hello " {i "brave new"} " World"}} or something alike, without forgetting any space inside quotes. {i It's obviously not acceptable in a wiki context made of 99% text!} _h4 2.3.3 How do lambdas bind values to arguments? _p Lambdas use arguments as Regular Expressions to replace their occurences found in the function's body - which is a string - by the given values: {pre 1) calling '{{lambda {:a :b} :a+:b is equal to {+ :a :b}} 3 4} 2) all occurences of :a and :b in ":a+:b is equal to '{+ :a :b}" are replaced by 3 and 4 in two steps: ":a+:b is equal to '{+ :a :b}" .replace( /:a/g, 3 ) -> "3+:b is equal to '{+ 3 :b}" "3+:b is equal to '{+ 3 :b}" .replace( /:b/g, 4 ) -> "3+4 is equal to '{+ 3 4}" 3) and "3+4 is equal to '{+ 3 4}" is returned for evaluation. } _p When the number of values is less then the function's arity, a new function is returned, storing the given values and waiting for the future values: {pre 1) calling with only one value '{{lambda {:a :b} :a+:b is equal to {+ :a :b}} 3} 2) all occurences of :a in the string ":a+:b is equal to '{+ :a :b}" are replaced by 3 ":a+:b is equal to '{+ :a :b}" .replace( /:a/g, 3 ) -> "3+:b is equal to '{+ 3 :b}" 3) and a new function '{lambda {:b} 3+:b is equal to {+ 3 :b}} is returned for a future call. } _p {b Note:} In order to avoid substitution conflicts, the string replacement process used by lambdas implies arguments to be prefixed by a distinctive char, say a colon. In the example shown this precaution obviously prevents the word {b equal} to be replaced by {b equ3l}! For a total security, it should be better to {i escape} arguments between two colons, {code :local_name:}, with the added benefit of enlighting them as local variables, to be compared with global constants called between curly braces, '{global_name}. _h4 2.3.4 Do lambdas create closures? _p {b No they don't!} This weakness is partially balanced by the fact lambdas accept a number of values different from their arity, (partial application with memorization, currying). As a useful application of this capability, this is how can be defined derivatives of a function {b f(x)}: {b f'(x), f''(x), f'''(x)}, ..., which are functions of {b x} and not values at a given {b x}: _ul 1) we define the derivative function: {pre '{def D {lambda {:f :h :x} {/ {- {:f {+ :x :h}} {:f {- :x :h}} } {* 2 :h}}}} -> {def D {lambda {:f :h :x} {/ {- {:f {+ :x :h}} {:f {- :x :h}} } {* 2 :h}}}} } _ul 2) we create the 1st, 2nd and 3rd derivatives of the function log for a given value of :h and as functions of :x: {pre '{def log' {lambda {:x} {D log 0.01 :x}} } -> {def log' {D log 0.01} } '{def log'' {lambda {:x} {D log' 0.01 :x} }} -> {def log'' {D {log'} 0.01} } '{def log''' {lambda {:x} {D log'' 0.01 :x} }} -> {def log''' {D {log''} 0.01} } } _ul 3) we can now call the 1st, 2nd and 3rd derivatives of log on a given value of x: {pre '{log' 1} -> {{log'} 1} // 1 '{log'' 1} -> {{log''} 1} // -1 '{log''' 1} -> {{log'''} 1} // 2 } _p Another application of this capability is that any agregate data can be built with lambdas, for instance {code pairs, lists, arrays, R/C numbers, 2D/3D vectors, ...}. We have seen an application of pairs, lists in part 1). This is how could be built the {code cons, car, cdr} functions usually associated to {b pairs}: {pre '{def cons {lambda {:a :b :m} {{:m :a} :b}}} '{def car {lambda {:p} {:p {lambda {:x :y} :x}}}} '{def cdr {lambda {:p} {:p {lambda {:x :y} :y}}}} } _p Because they are so useful, pairs - and lists and arrays - are actually built as primitives in the '{lambda talk}'s dictionary. }{{PAGE} _h4 2.3.5 Can special forms be nested? _p Yes you can! _ul {code def}s can be nested. But inner {code def}s are not local to the outer {code def}. There are no nested environments. So, in order to prevent names conflicts, a good practice - mimicking the OOP paradigm - is to prefix inner-defined names with the outer-defined names. For instance in the following example {code hypo.square} can be considered as a property of {code hypo}: {pre '{def hypo {def hypo.square {lambda {:x} {* :x :x}}} {lambda {:a :b} {sqrt {+ {hypo.square :a} {hypo.square :b}}}}} -> {def hypo {def hypo.square {lambda {:x} {* :x :x}}} {lambda {:a :b} {sqrt {+ {hypo.square :a} {hypo.square :b}}}}} '{hypo 3 4} -> {hypo 3 4} '{hypo 1 1} -> {hypo 1 1} } _ul {code if}s can be nested, leading to conditional sequences, for instance: {pre '{def inside? {lambda {:x :a :b} {if {equal? {+ 1 :x} NaN} then {u :x} is Not a Number else {if {< :x :a} then false else {if {< :x :b} then true else false}}}}} -> {def inside? {lambda {:x :a :b} {if {equal? {+ 1 :x} NaN} then {u :x} is Not a Number else {if {< :x :a} then false else {if {< :x :b} then true else false}}}}} '{inside? 0 1 10} -> {inside? 0 1 10} '{inside? 2 1 10} -> {inside? 2 1 10} '{inside? 11 1 10} -> {inside? 0 11 10} '{inside? foo 1 10} -> {inside? foo 1 10} } _ul {code lambda}s can be nested. This is an example where we want to compute the area of a right angle triangle [a,b,c] given by this formula: {code area = √{span {@ style="border-top:1px solid black"} s*(s-a)*(s-b)*(s-c)}} where {code s= (a+b+c)/2}: {pre 1) using lambdas: '{{lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}} }} :a :b :c {/ {+ :a :b :c} 2} }} 3 4 5} -> {{lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} } :a :b :c {/ {+ :a :b :c} 2}}} 3 4 5} 2) using let: '{{lambda {:a :b :c} {let { {:a :a} {:b :b} {:c :c} {:s {/ {+ :a :b :c} 2} }} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}} }}} 3 4 5} -> {{lambda {:a :b :c} {let { {:a :a} {:b :b} {:c :c} {:s {/ {+ :a :b :c} 2} }} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}}}} 3 4 5} } _ul Note that, because lambdas don't create closures, inner lambdas have no access to the outer lambdas arguments. This is why {code :a :b :c} must be duplicated in the above both versions. This workaround could be seen as a {i manual closure} ... which could be automatized in a next version of lambdatalk. Wait and see! _h4 2.3.6 What about iterative processes? _p Theoretically recursion can be used to build every iterative processes. For instance the well known factorial {b n!} {pre '{def ! {lambda {:a :b} {if {< :b 1} then :a else {! {* :a :b} {- :b 1}}}}} -> {def ! {lambda {:a :b} {if {< :b 1} then :a else {! {* :a :b} {- :b 1}}}}} '{! 6} -> {! 1 6} } _p But lambdatalk comes with three useful primitives [{code serie, map, reduce}] which can make things easier, safer and quicker. For instance, this is how can be computed a factorial without any recursion, knowing that +,*,-,/ accept any number of arguments: {pre '{* {serie 1 20}} -> {* {serie 1 20}} } _p and the Euler's number {b {E}} defined as an infinite serie: {b {code E = Σ{sub i=0}{sup ∞}[{sup 1}/{sub {* 1*2*..*i}]}}} {pre '{def euler {lambda {:n} {+ 1 {reduce {lambda {:a :b} {+ :a :b}} {map {lambda {:i} {/ 1 {* {serie 1 :i}}}} {serie 1 :n}}}}}} -> {def euler {lambda {:n} {+ 1 {reduce {lambda {:a :b} {+ :a :b}} {map {lambda {:i} {/ 1 {* {serie 1 :i}}}} {serie 1 :n}}}}}} '{euler 17} -> {euler 17} } _h4 2.3.7 What about mutability? _p Defined values can't be modified, lambdatalk is {b purely functional} and has no {code set!} special form. Mutations are exclusively made via functions' arguments. _h4 2.3.8 Why is lambdatalk easy to use by web designers? _p In Part 1) we have seen how a the '{lambda talk} syntax built over the HTML/CSS syntaxes can stay familiar to a web designer. However it's noticeable that the {code '{@ ...}} form breaks the previously claimed syntax unicity, there are no clean {b forms} in it and to many {i ugly} quoted strings used by HTML attributes and CSS rules! It was a matter of {b design choice}, in order to avoid any pollution of the dictionary with a myriad of CSS rules and giving web designers an access to {b standard HTML attributes and CSS rules} they are familiar with. And we have seen that any coder is able to hide behind names all those {i ugly} things. }{{PAGE} _h4 2.3.9 What about styles? _p CSS rules applied to the entire wiki are externalized as CSS files in the {b skins} folder and can be selected in the lambdatank's top-left menu. The current skin can be analyzed in the file [[skins/newone/CSS.css|skins/newone/CSS.css]]. Local CSS rules can be applied to a page using the {code '{style ...}} form. For instance in this page, a few tags have been overloaded like this: {pre '{style body { background:#fff; normal 1.0em Times New Roman; } #title { color:#fff; text-shadow:0 0 0; } #frame_view { width:100%; padding:0; border:0 solid; box-shadow:0 0 0; background:#fff; color:#000; } h1, h2, h3, h4, h5, h6 { margin-top:10px; margin-bottom:0px; } h1 { font-size:3.0em; color:black; } h2 { font-size:2.6em; color:red; } h3 { font-size:2.2em; color:green; } h4 { font-size:1.8em; color:blue; } h5 { font-size:1.4em; color:magenta; } h6 { font-size:1.0em; color:cyan; } } } _h4 2.3.10 What about scripts? _p The primitive {code '{input ...}} can easily embed short scripts via any onEvent attribute. For instance: {pre '{input {@ id="smart_hello" type = "text" placeholder = "Enter your name" onkeyup = "getId('yourName').innerHTML = 'Hello ' + getId('smart_hello').value + ' !'" }} '{h1 {@ id="yourName"}} } _p displays this text field in which you can enter your name: {p {input {@ id="smart_hello" type = "text" placeholder = "Please, enter your name" onkeyup = "getId('yourName').innerHTML = 'Hello ' + getId('smart_hello').value + ' !'" }}} {div {@ id="yourName" style="font:bold 4em georgia; color:blue"}} _p The primitive {code '{script ...}} can be used to insert more complex scripts. For instance: {pre '{div {@ id="output" style="..."}time: } '{input {@ type="submit" value="start" onclick="start()"}} '{input {@ type="submit" value="stop" onclick="stop()"}} '{script function start() { document.chrono = window.setInterval( function() { getId('output').innerHTML = 'time: ' + LAMBDATALK.eval_forms('{date}'); }, 1000 ); } function stop() { window.clearInterval( document.chrono ) } } } _p displays a digital watch: {div {@ id="output" style="font:bold 1.5em courier; color:red;"}time: } {input {@ type="submit" value="start" onclick="start()"}} {input {@ type="submit" value="stop" onclick="stop()"}} {script °° function start() { document.chrono = window.setInterval( function () { getId('output').innerHTML = 'time: ' + LAMBDATALK.eval_forms('{date}'); }, 1000 ); } function stop() { window.clearInterval( document.chrono ); } °°} _h4 2.3.11 What about libraries? _p Sets of user variables and functions can be stored in wiki pages and called elsewhere via a {code (require library)} call. Thus, the primitive dictionary can be extended as necessary with coherent modules carefully built to avoid name conflicts. For instance, functions defined in some {code lib_SVG_clock} page can be used via a {code (require ...)} to display a stylized clock: {pre '{center {{svg.clock 300 300} {svg.path 150 150 100 20 red 1} {svg.path 150 150 120 20 green 2} {svg.path 150 150 140 20 blue 3} {svg.digit} }} } {require lib_SVG_clock} {center {{svg.clock 300 300} {svg.path 150 150 100 20 red 1} {svg.path 150 150 120 20 green 2} {svg.path 150 150 140 20 blue 3} {svg.digit} } } }{{PAGE} _h4 2.3.12 What about macros? _p Macros in lambdatalk bring the power of regular expressions directly in the language. As an example, this is how we define an array of ten numbers and display them squarred using the lambdatalk syntax: {pre '{def A {array {serie 1 10}}} -> {def A {array {serie 1 10}}} '{map {lambda {:i} {* {array.nth {A} :i} {array.nth {A} :i}}} {serie 0 {- {array.length {A}} 1}}} -> {map {lambda {:i} {* {array.nth {A} :i} {array.nth {A} :i}}} {serie 0 {- {array.length {A}} 1}}} } _p It's rather difficult to read. Thanks to a small set of helper functions and a single macro {pre '{def K.disp {lambda {:arr} {array.disp {:arr}} }} -> {def K.disp {lambda {:arr} {array.disp {:arr}}}} '{def K.nth {lambda {:arr :i} {array.nth {:arr} :i} }} -> {def K.nth {lambda {:arr :i} {array.nth {:arr} :i}}} '{def K.range {lambda {:arr} {serie 0 {- {array.length {:arr}} 1} }}} -> {def K.range {lambda {:arr} {serie 0 {- {array.length {:arr}} 1}}}} '{macro ([\w:]+?)\[([\w:]*?)\] to {if {empty? €2} then {K.disp €1} else {if {equal? €2 range} then {K.range €1} else {K.nth €1 €2}}}} } _p we can write the previous expression in a more readable way: {macro ([\w:]+?)\[([\w:]*?)\] to {if {empty? €2} then {{lambda {:arr} {array.disp {:arr}}} €1} else {if {equal? €2 range} then {K.range €1} else {K.nth €1 €2}}}} {pre '{map {lambda {i} {* A [i] A [i]}} A [range]} -> {map {lambda {i} {* A[i] A[i]}} A[range]} } _p In this example it's easy to see a regular expression based syntax {u before} the word {b to} and a lambdatalk based syntax {u after} with a nested {code if then else} control structure. _p '{lambda talk} comes with a predefined small set of useful macros allowing writing titles, paragraphs and item lists without curly braces: {pre _{span}h1 TITLE cr stands for '{h1 TITLE} and alike for h2, h3, h4, h5, h6 _{span}p Some paragraph ... cr stands for '{p Some paragraph ...} _{span}ul list item 1 cr _{span}ul list item 1 cr _{span}ul list item 1 cr stands for '{ul {li list item 1} {li list item 2} {li list item 3} } } _p These simplified alternatives, avoiding curly braces as much as possible, are fully used in this document. _h4 2.3.13 Where does lambdatalk come from? _p Not exactly from Lisp, built on {b Lis}t {b P}rocessing, but from the {b lambda calculus}{ref 17} defined by Alonzo Church in the thirties and built on words substitution. Following the {b lambda calculus} a '{lambda talk} expression could be defined like this: {pre {center expression ::= word | abstraction | application }} _p Where {ol {li a {b word} is any sequence of chars except spaces and '{}, and is evaluated to itself,} {li an {b abstraction} is a form '{lambda {words} expression}, and is evaluated to the reference of an anonymous function,} {li an {b application} is a form '{abstraction expression}, and is evaluated to a sequence of words.} } _p At this point '{lambda talk} knows nothing but text substitutions. For instance: {pre 1) words Hello World -> Hello World 2) abstraction '{lambda {o a} oh happy day!} -> lambda_1234 3) application '{{lambda {o a} oh happy day!} oOOOo aaAAaa} -> oOOOoh haaAAaappy daaAAaay! } _p Amazingly nothing more is needed to compute expressions such {b 6! = 1*2*3*4*5*6 = 720}: {pre {@ style="white-space:pre-wrap;"} °° {{λ {:n} {{λ {:p} {:p {λ {:x :y} :y}}} {{:n {λ {:p} {{λ {:a :b :m} {{:m :a} :b}} {{λ {:n :f :x} {:f {{:n :f} :x}}} {{λ {:p} {:p {λ {:x :y} :x}}} :p}} {{λ {:n :m :f} {:m {:n :f}}} {{λ {:p} {:p {λ {:x :y} :x}}} :p} {{λ {:p} {:p {λ {:x :y} :y}}} :p}}}}} {{λ {:a :b :m} {{:m :a} :b}} {λ {:f :x} {:f :x}} {λ {:f :x} {:f :x}}}}}} {λ {:f :x} {:f {:f {:f {:f {:f {:f ... total 6 times}}}}}}}} -> {λ {:f :x} {:f {:f {:f {:f {:f {:f ... total 720 times}...} °°} _p where {b λ} stands for {b lambda} to be short. Read more in {b calc2talk}{ref 18}. _p Usually the {b lambda calculus} comes with the Church numbers and a set of operators, [{code def, succ, add, mul, succ, power, cons, car, cdr, pred, subtract, ..., Y-combinator}] to make things easy to write and read. And theoretically, we could go on this way to build the majority of '{lambda talk}'s functionalities. But in order to bring a bit of humanity - and make coding much more easy - it's more reasonable to play with readable defined names and populate the dictionary with some useful primitive functions built on the browser's foundations, Javascript's numbers, Math operators and functions, HTML tags, CSS rules, and some others. With an augmented set of special forms, [lambda, def, if, let, quote, ...], all these "improvements" lead to a more usable and effective language, '{lambda talk}. }{{PAGE} _h2 conclusion }{{PAGE} _p The '{lambda way} project is essentially built on a 30kb PHP file and a 60kb JS file. It's free of any external dependancies, '{lambda talk} can be used out of '{lambda tank} and embedded in any other environment. The underlying PHP+JS code is small and easy to read, edit and improve. It's a free software under the {b GNU GPL} licence. Its {b 100kb} archive is easy to [[download & install|?view=download]] on any web account running PHP. _p '{lambda talk} is a small but complete programmable programming language offering tools which can be used, in any modern web browser and on any device (from desktop PCs to smartphones) at three levels of increasing complexity: {ul {li with a handful of basic commands any {b author} can easily create minimally structured documents made of words and pictures,} {li any {b web designer} can find a full set of HTML tags and CSS rules to enrich them,} {li and any {b coder} can fit specific needs and make pages compositing more easy by extending the language's built-in functionalities.} } _p Everybody sharing a clear, unique and coherent notation allowing to produce rich and dynamical documents in a true collaborative work. Commenting this work, somebody wrote this: « Reminds me of {b John McCarthy}'s lament at the W3C's choice of SGML as the basis for HTML: "{i An environment where the markup, styling and scripting is all s-expression based would be nice.}" » _p This was the goal of the {b lambdaway} project{ref 19}. _p Villeneuve de la Raho, 2016/11/22 _h3 references {div {@ style="white-space:pre-wrap"} - {back_ref 1} [[https://en.wikipedia.org/wiki/Wiki|https://en.wikipedia.org/wiki/Wiki]] - {back_ref 2} [[https://en.wikipedia.org/wiki/Wiki_markup|https://en.wikipedia.org/wiki/Wiki_markup]] - {back_ref 3} [[http://epsilonwiki.free.fr/lambdaway/?view=latex|http://epsilonwiki.free.fr/lambdaway/?view=latex]] - {back_ref 4} [[http://epsilonwiki.free.fr/lambdaway/?view=PDF|http://epsilonwiki.free.fr/lambdaway/?view=PDF]] - {back_ref 5} [[http://epsilonwiki.free.fr/lambdaway/?view=curl|http://epsilonwiki.free.fr/lambdaway/?view=curl]] - {back_ref 6} [[http://epsilonwiki.free.fr/lambdaway/?view=LML|http://epsilonwiki.free.fr/lambdaway/?view=LML]] - {back_ref 7} [[http://epsilonwiki.free.fr/lambdaway/?view=skribe|http://epsilonwiki.free.fr/lambdaway/?view=skribe]] - {back_ref 8} [[http://docs.racket-lang.org/scribble/|http://docs.racket-lang.org/scribble/]] - {back_ref 9} [[http://epsilonwiki.free.fr/lambdaway/?view=SXML|http://epsilonwiki.free.fr/lambdaway/?view=SXML]] - {back_ref 10} [[http://people.cs.aau.dk/~normark/laml/papers/web-programming-laml.pdf|http://people.cs.aau.dk/~normark/laml/papers/web-programming-laml.pdf]] - {back_ref 11} [[http://docs.racket-lang.org/pollen|http://docs.racket-lang.org/pollen/]] - {back_ref 12} [[https://fr.wikipedia.org/wiki/Suite_de_Fibonacci|https://fr.wikipedia.org/wiki/Suite_de_Fibonacci]] - {back_ref 13} [[https://en.wikipedia.org/wiki/De_Casteljau's_algorithm|https://en.wikipedia.org/wiki/De_Casteljau's_algorithm]] - {back_ref 14} [[https://en.wikipedia.org/wiki/Simon_Peyton_Jones|https://en.wikipedia.org/wiki/Simon_Peyton_Jones]] - {back_ref 15} [[https://www.cnet.com/news/google-subtracts-mathml-from-chrome|https://www.cnet.com/news/google-subtracts-mathml-from-chrome-and-anger-multiplies/]] - {back_ref 16} [[https://en.wikipedia.org/wiki/Ward_Cunningham|https://en.wikipedia.org/wiki/Ward_Cunningham]] - {back_ref 17} [[http://jwodder.freeshell.org/lambda.html|http://jwodder.freeshell.org/lambda.html]] - {back_ref 18} [[http://epsilonwiki.free.fr/lambdaway/?view=calc2talk|http://epsilonwiki.free.fr/lambdaway/?view=calc2talk]] - {back_ref 19} [[http://epsilonwiki.free.fr/lambdaway/|http://epsilonwiki.free.fr/lambdaway/]] - ... - [[PDF version|data/lambdaway_20161122.pdf]] generated from this wiki page - ... - ... } } {center {i This paper has been submitted to [["lambda DAλS" 9-10 february 2017 krakow poland|http://www.lambdadays.org/lambdadays2017]] and rejected before being submitted to any reviewers.} } {{hide} {def COL_NUMBER 2} {def PAGE div {@ style="column-count:{COL_NUMBER}; -moz-column-count:{COL_NUMBER}; -webkit-column-count:{COL_NUMBER}; border-top:30px solid #ccc; margin:10px 0; "}} {def codeview {lambda {:col} div {@ style="{if {= :col 1} then color:#000; background:#eee; font:normal 0.9em courier new; else color:#000; background:#fff; font:normal 1.2em georgia;} white-space:pre-wrap; padding:10px; margin:5px 0;"} {div {@ style="font-size:0.6em; text-align:right; margin:-10px 0px -30px -8px;"} {if {= :col 1} then code else view} }}} {def ref {lambda {:i} {a {@ name="_:i" href="#:i"}{sup [:i]}} }} {def back_ref {lambda {:i} {b {a {@ name=":i" href="#_:i"}[:i]}} }} } {style °° body { background:#fff; normal 1.0em Times New Roman;} #title { color:#fff; text-shadow:0 0 0; } #frame_view { width:100%; padding:0; border:0 solid; box-shadow:0 0 0; background:#fff; color:#000; } h1, h2, h3, h4, h5, h6 { margin-top:10px; margin-bottom:0px; } h1 { font-size:3.0em; color:black; } h2 { font-size:2.6em; color:red; } h3 { font-size:2.2em; color:green; } h4 { font-size:1.8em; color:blue; } h5 { font-size:1.4em; color:magenta; } h6 { font-size:1.0em; color:cyan; } p { font:normal 1.0em Times New Roman;} ul { font:normal 1.0em Times New Roman;} °°}