SFPW_2014 :: YAW_20140903Yet Another Wiki - epsilonwiki

Sep 5, 2014 - capabilities of a programming language with first class user functions, recursion ... lambdatalk will be progressively introduced, starting as a simple and coherent notation ... documents in HTML or PDF (via Latex) form. Scribble helps to .... 1) Thanks to the Javascript Math object, lambdatalk comes with.
2MB taille 2 téléchargements 292 vues
+

SFPW_2014 :: YAW_20140903Yet

Another Wiki

Alain Marty Engineer Architect 66180, Villeneuve de la Raho, France [email protected]

Abstract alphawiki is a small environment working on top of any modern browser for authoring, styling and scripting dynamic WEB pages using a simple and unique LISP-like syntax, lambdatalk. Initialy built on a loop working on a single Regular Expression and a small dictionary of less than hundred primitive functions, lambdatalk provides a coherent S-expression based notation to write and style text in a wiki. Then, with a minimal set of 3 special forms, [lambda, def, if], lambdatalk offers some of the capabilities of a programming language with first class user functions, recursion, loops, scalar and non scalar datas like arrays, vectors, polynoms and some other things allowing to extend its functionalities. The present paper will focus on lambdatalk. In a first section lambdatalk will be progressively introduced, starting as a simple and coherent notation usable by web-designers (and even by beginners), to become a true programming language usable by a coder. In a second section will be detailed the Regular Expressions based underlying engine, to demonstrate how such an iconoclast choice, forgetting the standard mechanism popularised by LISP and its dialects, can be seen as an acceptable answer in a wiki context.

Keywords Lisp, Scheme, Javascript, Regular Expressions, CMS, wiki.

1.......Introduction 1.1......The context Web browsers parse data such as HTML code, CSS rules and JS scripts stored on the server side and display rich multimedia dynamic pages on the client side. Script languages such as PHP and Javascript allow strong interactions with these data leading to web applications. Hundreds of engines have been built, managing files on the server side and interfaces on the client side, such as Wordpress, MediaWiki, Joomla, Drupal. The de facto standard Markdown syntax is widely used to simplify text markup, but is not intended to be used for an easy styling and even less for scripting. Works have been done to build unified syntaxes, for instance: Skribe [1] by Erick Gallesio and Manuel Serrano: a functional programming language designed for authoring documents, such as web pages or technical reports. It is built on top of the Scheme programming language. Its concrete syntax is simple and it looks familiar to anyone used to markup languages., Scribble [2] by Matthew Flatt and Eli Barzilay: The Racket Documentation Tool, is a collection of tools for creating prose documents in HTML or PDF (via Latex) form. Scribble helps to write programs that are rich in textual content, whether the content is prose to be typeset or any other form of text to be generated programmatically, LAML [3] by Kurt Nørmark: The main idea in this work is to bring XML and HTML into the domain of the Scheme programming language, and as such let the author and programmer use the power of abstraction and programmed solutions when he or she is doing web work. All of these projects, closely related to the Scheme language, are great and powerful. With the plain benefit of existing Scheme implementations they make a strong junction between the markup,

styling and programming syntaxes. But these tools are definitively devoted to smart developers and not to webdesigners and even less to beginners. It's in order to give them a simplified common environment where could be done a collective work, that alphawiki and its language, lambdatalk, have been conceived.

1.2......In this paper The 100kb alphawiki's engine can be easily installed on any ISP. It's mainly built on two small "cylinders": 1) PHP.php: on the server side a 460 lines PHP code does everything about pages data, reading and writing, security, administration, ... 2) JS.js: on the client side a 1000 lines JS code manages the user interface and contains the code interpreter. The present contribution will forget alphawiki and will focus on the interpreter, lambdatalk: in "2. Using lambdatalk" will be progressively shown how to write, style and code in lambdatalk, in "3. Lambdatalk inside" will be detailed the code of the lambdatalk underlying Javascript engine, in order to explain and justify the design's rather iconoclast choice.

2.......Using lambdatalk 2.1.......Writing some code An alphawiki website is made of several pages sharing the same appearance. Each page is edited (by authorized users) via a frame editor, evaluated in real-time and displayed in the wiki page. This is an example showing the linked frame editor and wiki page:

Consider a more useful code written in the wiki's editor frame: {ul {li Words can be {b bold}, {i italicized}, {u underlined} (and {b {i {u bold, italicized, underlined}}}).} {li I'm fan of {a {@ href="http://www.pixar.com"}PIXAR}.} {li {span {@}Hello World}.} {li The hypotenuse of a right rectangle of sides 3 and 4 is equal to {sqrt {+ {* 3 3} {* 4 4}}}.} {li {input {@ type = "text" placeholder = "Please, enter your name" onkeyup="getId('yourName').innerHTML = 'Hello '+this.value+' !'"}}}} {h1 {@ id="yourName"}} This is the result displayed in the wiki page: Words can be bold, italicized, underlined (and bold,

italicized, underlined). I'm fan of PIXAR.

Hello World. The hypotenuse of a right rectangle of sides 3 and 4 is equal to 5.

pow, min, max, PI, E, // OTHERS note, note_start, note_end, back, post, drag, listing, show, lightbox, forum, editable, lib, require, lisp, lc, sheet, date, serie, map, reduce, first, rest, nth, length, equal?, empty?, chars, charAt,

John & Ward

Hello John & Ward ! The lambdatalk code is made of nested s-expressions sharing the same shape: {first rest}: 1) first must be a word belonging to a dictionary. In the example shown above we can distinguish some of them: ul starts an unordered list, li starts a list item, b, i, u are for "bold", "italic", "underline", @ opens a list of HTML and CSS attributes, a creates a link waiting for attributes, here an URL via the HTML attribute "src" span build an inline container waiting for HTML attributes, here a "style" list of CSS rules, sqrt is a function computing the square root of a number, + and * are operators adding and multiplying numbers, input creates an input textfield and a behaviour driven by a Javascript code, and h1 starts a title of level one. 2) rest can be any text containing or not s-expressions, 3) first and rest are framed between curly braces, {}, acting as escape characters launching the evaluation process. Concerning the HTML attributes and CSS rules, it was a design choice to respect the well known standard syntaxes and to group them in a single {@ attributes} s-expression. This choice keeps things simple for a web-designer, and beyond, with a little help of a coder, these syntaxes can be hidden to the beginner, as it will be seen in 2.5.8.

2.2.......The evaluation process The lambdatalk's interpreter evaluates nested s-expressions from the terminal s-expressions (which don't contain anymore s-expression) to the root. The evaluation process is the application of a function, belonging to the dictionary and linked to the word first, to the arguments contained in rest. For instance: in {u Hello World}, u applies the HTML tag u to Hello World and returns < u>Hello World< /u> to the browser which will display Hello World, in {* 3 4} * calls the Javascript operator * which returns 12, {* 1 x} will return NaN because x is Not A Number, and an unevaluable s-expression, for instance {foo bar}, will be returned unevaluated as it is: {foo bar}, without any error message polluting the text in the wiki page! Note that in {u Hello World}, Hello World is not quoted. In lambdatalk strings do not need to be put between quotation marks or anything else. It's an essential point in a wiki context!

2.3.......The dictionary The lambdatalk's core dictionary contains a list of words linked to primitive functions: // HTML @, div, span, a, ul, ol, li, dl, dt, dd, table, tr, td, h1, h2, h3, h4, h5, h6, p, b, i, u, pre, center, sup, sub, del, br, hr, blockquote, code, img, textarea, embed, canvas, iframe, input, script, style, mailto, // MATH >, < , >=, 5 {hypo 1 1} -> 1.4142135623730951

2.4.2.2.......scalar constants 1) Thanks to the Javascript Math object, lambdatalk comes with two fundamental irrational numbers: PI and E. Writing {PI} displays 3.141592653589793. PI can be considered as a reference to the content {PI} pointed by it. Note that this behaviour is different from the standard constant's definition in other languages, for instance in Lisp dialects. In a wiki context we should like to write the name of a constant without launching its evaluation. We can remember how the value of PI is called in a spreadsheet's cell (ie. Excel or OpenOffice.calc) : =PI(). 2) Sometimes we have to give a name to some user constant value, for instance to a simplified value of PI, say 3.1416. Following a syntax similar to the previous one used for naming functions, we can write {def myPI 3.1416} which returns myPI. As previously, writing {myPI} will return its value.

3) We can also give a name to a constant s-expression, provided it contains evaluable terms, for instance the golden number Φ: {def PHI {/ {+ 1 {sqrt 5}} 2}} -> PHI {PHI} -> 1.618033988749895 Complex bunches of CSS rules can be called by a simple name: {def blue_georgia span {@}} {{blue_georgia} Blue Georgia} will display: Blue

Georgia.

2.4.2.3.......non scalar constants lambdatalk makes easy the definition of non scalar constants, such arrays, polynoms, vectors, complex numbers and some others. For instance the following code: {def V 0.123 0.456} = [ {V} ] V.x = {first {V}} & V.y = {rest {V}} the dimension of V is {length {V}} {def V.norm {lambda {:v} {sqrt {+ {* {first {:v}} {first {:v}}} {* {rest {:v}} {rest {:v}}}}}}} {V.norm V} displays: V = [ 0.123 0.456 ] V.x = 0.123 & V.y = 0.456 the dimension of V is 2 V.norm 0.4722975756871932 More complex vector algebra could be built in a similar way, as it can be seen in the alphawiki++ website.

2.4.3.......conditions (if) lambdatalk comes with two boolean numbers true and false and some related primitive functions. For instance: {< 11 12} -> true {> 11 12} -> false {not true} -> false {or {< 11 12} {> 11 12}} -> true {and {< 11 12} {> 11 12}} -> false {if {< 11 12} then YES else NO} -> YES The if function deserves a special attention. In fact, beside lambda and def, if is a third special form used via this syntax: {if bool_term then then_term else else_term} which evaluates either then_term or else_term according to the value of its bool_term. For instance: {if {
720. But what about computing the 100 first numbers? We must think of another way to compute the product. We can think recursively and write a function called factorial: {def factorial {lambda {:n} {if {< :n 1} then 1 else {* :n {factorial {- :n 1}}}}}} {factorial 6} {factorial 100} which will display: 720 9.33262154439441e+157 defs can be nested, and it's easy to write a tail-recursive version: {def ifac {def _ifac {lambda {:result :n} {if {< :n 1} then :result else {_ifac {* :result :n} {- :n 1}}}}} {lambda {:n} {_ifac 1 :n}}} 1*2*3*4*5*6*...*21 = {ifac 21} which will display: 1*2*3*4*5*6*...*21 = 51090942171709440000

2.5.2.......loops Thanks to recursion loop structures can be built. lambdatalk has no "do" function, and we can define one: {def do {lambda {:f :from :a :to :b step :d} {map :f {serie :a :b :d}}}} -> do {do square from 1 to 100 step 0.5} -> 1 2.25 4 6.25 9 12.25 16 20.25 25 30.25 36 42.25 49 56.25 64 72.25 81 90.25 100

2.5.3.......global and local variables (let) Names given to functions and constants are in the global scope (of the wiki page). Lisp and its dialects have a let special forms to define local values in a function's body. Actually, in Lisp, the let special form is nothing but a sugar using the lambda special form. We will use lambdas arguments to get the same result. For instance, the area of a triangle [a,b,c] is given by this formula : Let a,b,c be the sides of a triangle, then area = sqrt[s*(s-a)*(s-b)*(s-c)] where s = (a+b+c)/2 It's better to compute once the value s used 4 times and we write: {def triangle {lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} } :a :b :c {/ {+ :a :b :c} 2}} }} {triangle 3 4 5} -> 6 where the fourth argument of the internal lambda :s is used as a local variable.

2.5.4.......partially called functions (curry)

In lambdatalk a function can be called with a number of values different from the number of its arguments. For instance:

x1 = [-0.5 , -0.8660254037844386] x2 = [-0.5 , +0.8660254037844386]

{def boo {lambda {:a :b} {+ :a :b}}} -> boo

2.5.6......mathematical notations

{boo} -> lambda_6195 // it's a function waiting for 2 values {boo 1} -> lambda_3262 // it's now a function waiting for 1 value {boo 1 2} -> 3 // called with two values, returns a value {{boo 1} 2} -> 3 // called in two steps, returns a value {boo 1 2 3} -> 3 // the extra value is ignored

As long as the mathML tags won't be recognized by Chrome, lambdatalk can be used to display mathematical formulas.

As an application, we can easily write derivatives of any order: {def D {lambda {:f :x} {/ {- {:f {+ :x 0.01}} {:f {- :x 0.01}} } 0.02} }} -> D {def cubic {lambda {:x} {* :x :x :x}}} -> cubic {round {round {round {round {round

{cubic 2}} {{D cubic} 2}} {{D {D cubic}} 2}} {{D {D {D cubic}}} 2}} {{D {D {D {D cubic}}}} 2}}

-> -> -> -> ->

8 12 12 6 0

2.5.5.......quadratic equation In lambdatalk words and numbers can be easily mixed, without any string quotation or any special printing format. This is an example giving the roots of the quadratic equation ax2 + bx + c = 0: {def equation {lambda {:a :b :c} {{lambda {:a :b :c :d} discriminant = :d {if {> :d 0} then 2 real roots : x1 = {/ {- {- :b} {sqrt :d}} {* 2 :a}} x2 = {/ {+ {- :b} {sqrt :d}} {* 2 :a}} else {if {= :d 0} then 1 double real root : x = {/ {- :b} {* 2 :a}} else 2 complex roots : x1 = [{/ {- :b} {* 2 :a}} , -{/ {sqrt {- :d}} {* 2 :a}}] x2 = [{/ {- :b} {* 2 :a}} , +{/ {sqrt {- :d}} {* 2 :a}}] }} } :a :b :c {+ {* :b :b} {* 4 :a :c}}} }} 1) {b equation [1 -1 1]} -> {equation 1 -1 1} 2) {b equation [1 -2 1]} -> {equation 1 -2 1} 3) {b equation [1 1 -1]} -> {equation 1 1 -1} displays: 1) equation [1 -1 1] -> discriminant = 5 2 real roots : x1 = -0.6180339887498949 x2 = 1.618033988749895 2) equation [1 -2 1] -> discriminant = 0 1 double real root : x=1 3) equation [1 1 -1] -> discriminant = -3 2 complex roots :

{def numero {lambda {:n} {div {@ style= "float:right; font-size:12px;"}:n}}} {def radicand {@ style= "text-decoration:overline;"}} {def quotient {lambda {:h} {@}}} {def quotient_line {lambda {:w} {div {@}}}} x = {div {quotient 1.0} {div -b ± √{span {radicand} b{sup 2} - 4ac}} {quotient_line 100} {div 2a}} {numero 1.1} Δf(x,y,z) = {div {quotient 1.0} {div ∂{sup 2}f(x,y,z)} {quotient_line 60} {div ∂x{sup 2}}} + {div {quotient 1.0} {div ∂{sup 2}f(x,y,z)} {quotient_line 60} {div ∂y{sup 2}}} + {div {quotient 1.0} {div ∂{sup 2}f(x,y,z)} {quotient_line 60} {div ∂z{sup 2}}} {numero 1.2} displays: -b ± √b2 - 4ac 2a ∂2f(x,y,z) ∂2f(x,y,z) ∂2f(x,y,z) Δf(x,y,z) = + + ∂x2 ∂y2 ∂z2 x=

1.1 1.2

2.5.7.......drawing in a wiki page Playing with bezier curves, lambdatalk and CSS can be done apart from any canvas. Writing: {def V.x {lambda {:p} {first {:p}}}} {def V.y {lambda {:p} {rest {:p}}}} {def intp3 {lambda {:a0 :a1 :a2 :a3 :t :u} {round {+ {* :a0 :u :u :u 1} {* :a1 :u :u :t 3} {* :a2 :u :t :t 3} {* :a3 :t :t :t 1}}}}} {def bezier {lambda {:p0 :p1 :p2 :p3 :t} {intp3 {V.x :p0} {V.x :p1} {V.x :p2} {V.x :p3} :t {- 1 :t}} {intp3 {V.y :p0} {V.y :p1} {V.y :p2} {V.y :p3} :t {- 1 :t}}}} {def dot {lambda {:x :y :r :bord :back} {span {@}}}}

{def {def {def {def {def {def

P0 200 30} P1 410 80} P2 200 250} P3 410 170} P0123 P0 P1 P2 P3} P0132 P0 P1 P3 P2}

{dot {P0} 20 black yellow} {dot {P1} 20 black cyan} {dot {P2} 20 black cyan} {dot {P3} 20 black yellow} {map {lambda {:t} {dot {bezier {P0123} :t} 5 black red}} {serie -0.2 1.2 0.0125}} {map {lambda {:t} {dot {bezier {P0132} :t} 5 black blue}} {serie -0.2 1.2 0.0125}}

Spreadsheets are known to be a good illustration of the functional approach. With lambdatalk it's possible to insert a spreadsheet in a wiki page and to make some calculus. For instance, the symbolicexpression {+ {lc 2 4} {lc 3 4} {lc 4 4}} written in the cell L6C4 will display the sum of the contents of cells L2C4, L3C4 and L4C4, as it can be seen in the figure below:

will display these two cubic curves anywhere in the wiki page:

2.5.8.......end users are not forgotten! Let's look at the first code shown in this paper. In order to make things easier for the beginner, lambdatalk comes with some "sugar" for blocks between line returns, ie. titles, paragraphs and lists [h1..6, p, ul, ol] and for external and internal links [a]. With some help of a coder defining a couple of useful functions: {def blue span {@}} {def hello-input {lambda {:hi} {input {@ type="text" placeholder="Please, enter your name" onkeyup="getId('yourName').innerHTML = ' :hi ' + this.value + ' !'" }} {h1 {@ id="yourName"}}}} this code could be written, without any HTML attributes, CSS rules and quoted strings: _ul Words can be {b bold}, {i italicized}, {u underlined} (and {b {i {u bold, italicized, underlined}}}). _ul I'm fan of [ [PIXAR|http://www.pixar.com]]. _ul {{blue}Hello World}. _ul The hypotenuse of a right rectangle of sides 3 and 4 is equal to {sqrt {+ {* 3 3} {* 4 4}}}. _ul {hello-input Bonjour}

2.5.9.......plugins Lambdatalk can call more complex (Java)scripts executed interactively in the wiki page via lambdatalk functions. It becomes possible to integrate a Table of Content, a Forum, a Lightbox, a 2D Drawing, a Ray-Tracing, 3D shapes, Fractals, a Lisp, a spreadsheet.

alphawiki can be considered as a stack of pages. In the same way, a spreadsheet embedded in a page can be viewed as a grid of micro-pages with all the lambdatalk's capabilities. Numerous usages of lambdatalk and several more complex examples of its functionalities can be seen in the alphawiki website. We have seen how, built on a dictionary of hundred primitive functions and a minimal set of special forms, [lambda, def, if], lambdatalk comes with a unique, coherent and simple syntax to write, style and script web pages. The underlying engine of lambdatalk will now be introduced in the following section.

3.......Lambdatalk inside In the alphawiki context long sequences of words must stay unevaluated, it's essential! One must be able to write them without the concern of any quotation. Instead of {b "Hello World"}, one must be able to simply write {b Hello World} to get Hello World. And one must be able to write the word PI without any quotation {q PI} or 'PI. Writing {PI} will return its value if needed. It appears that the Scheme based projects mentionned previously (1.1 The context) don't give any (simple) answer to this question. It's the main reason why, in Lambdatalk, the design choice was to forget the Lisp's dialects standard mechanism and to build another one based on a powerful tool dedicated to strings: the Regular Expressions.

3.1.......the evaluate() function Well balanced s-expressions {first rest} are caught and evaluated by the evaluate() function. The evaluation process is made in two stages: a pre-processing phase and a single loop. When first is one of three special forms [if, lambda,def], the evaluation is made in the pre-processing phase. For the others (primitive and user functions), the evaluation works from the inside out, basically matching a terminal s-expression via a Regular Expression, evaluating that form, replacing it with the result, and looping until the input and output are identical. This evaluation is made in a unique global environment, named dictionary, according to the values of first and rest. var evaluate = function(str) {

str = preprocessing(str); var bal = balance(str); if (bal.left != bal.right) str = 'none'; else { str = eval_special_forms(str); str = eval_sexprs(str); } return str; };

3.2.......the main Regular Expression lambdatalk uses a single Regular Expression to catch terminal s-expressions: var loop_rex = /\{([^\s{}]*)(?:[\s]*)([^{}]*)\}/g; 1) / start of the regexp 2) \{ begins with a { 3) ([^\s{}]*) everything except "\s{}": first 4) (?:[\s]*) zero or several spaces 5) ([^{}]*) everything except "{}" : rest 6) \} ends with a } 7) / end of the regexp 8) g go next -

var eval_lambdas = function(str) { while (true) { var s = catch_sexpression('lambda', str); if (s === 'none') break; str = str.replace( '{lambda '+s+'}',eval_lambda(s.trim())); } return str; }; var eval_lambda = function (s) { s = eval_lambdas(s); // lambdas can be nested var name = 'lambda_' + Math.floor(Math.random()*1000000), args = s.substring(1, s.indexOf('}')) .trim().split(' '), body = s.substring(s.indexOf('}')+1) .trim(), reg_args = []; for (var i=0; i < args.length; i++) reg_args[i] = RegExp( args[i], 'g');

dict[name] = function () { var vals = arguments[0] .replace(/\s{2,}/g, ' ') .trim().split(' '); return function (bod) { if (vals.length < args.length) { for (var i=0; i < vals.length; i++) bod = bod.replace(reg_args[i],vals[i]); 3.3.......evaluating S-expressions var _args = Following a code snippet shared by Steven Levithan [4], the args.slice(vals.length).join(' '); eval_sexprs() function is a one line single loop using the bod = eval_lambdas( previous Regular Expression to catch s-expressions and a '{lambda {'+_args+'}'+bod+'}'); do_apply() function to replace them by their value: } else if (vals.length==args.length) { for (var i=0; i < vals.length; i++) var eval_sexprs = function(str) { bod = bod.replace(reg_args[i],vals[i]); while } else { // vals.length > args.length (str != (str=str.replace(loop_rex,do_apply))); for (var i=0; i < args.length; i++) return str; bod = bod.replace(reg_args[i],vals[i]); }; } return bod; var do_apply = function() { }(body); var first = arguments[1] || '', }; rest = arguments[2] || ''; return name; if (dict.hasOwnProperty(first)) }; return dict[first].apply(null, [rest]); else 3.6.......evaluating defs return hide_braces( The eval_def() function catches every s-expressions having '< u>{' + first + ' ' + rest + '}< /u>'); }; this shape {def name body} and replaces it by the given name. If first belongs to the dictionary it is applied to rest and the value is returned. If not, the s-expression is returned unevaluated.

3.4.......evaluating special forms During the pre-processing phase, the special forms are caught in this order: 1) if, 2) lambda, 3) def and evaluated by specific functions. var eval_special_forms = function(str) { str = eval_ifs(str); str = eval_lambdas(str); str = eval_defs(str, true); return str; };

3.5.......evaluating lambdas The eval_lambdas() function catches every s-expressions having this shape {lambda {:args} body} and replaces it by a random name. This name is associated with a function which will replace in the body the occurrences of the arguments by the given values when the function is called. Prefixing arguments names by a distinctive character, ie. a colon, avoids any conflict in the replacement process.

var eval_defs = function(str, flag) { while (true) { var s = catch_sexpression('def', str); if (s === 'none') break; str = str.replace('{def '+s+'}', eval_def(s.trim(), flag)); } return str; }; var eval_def = function (s, flag) { s = eval_defs( s, false ); // defs can be nested var name = s.substring(0, s.indexOf(' ')) .trim(), body = s.substring(s.indexOf(' ')) .trim(); dict[name] = (dict.hasOwnProperty(body))? dict[body] : function () { return body }; delete dict[body]; return (flag)? name : ''; };

3.7.......evaluating ifs We have seen that the {if bool_term then then_term

else else_term} special form deserves a special attention. The evaluation of the then_term and the else_term must be delayed until the boolean_term gets a value. The process is made in two steps. During the pre-processing phase the eval_ifs() function replaces the special form by {_if_ bool_term then then_term else else_term} where _if_ is an associated primitive function and the then_term and else_term have been "deactivated". During the s-expressions evaluation phase, this function will return the then_term or the else_term, "reactivated" according to the value of the bool_term. var eval_ifs = function(str) { while (true) { var s = catch_sexpression('if', str); if (s === 'none') break; str = str.replace('{if '+s+'}', eval_if(s.trim())); } return str; }; var eval_if = function(s) { s = eval_ifs(s); // ifs can be nested var pif = parse_if( s ); return '{_if_ ' + pif[0] + ' then ' + hide_braces(pif[1]) + ' else ' + hide_braces(pif[2]) + '}'; }; var parse_if = function(s) { var index1 = s.indexOf('then'), index2 = s.indexOf('else'), bool_term = s.substring(0,index1) .trim(), then_term = s.substring(index1+5,index2) .trim(), else_term = s.substring(index2+5) .trim(); return [bool_term, then_term, else_term]; };

3.8.......some primitives in the dictionary The dictionary is an associative array of primitive functions. Previously, we have seen that the if special form was closely related to a function belonging to the dictionary, _if_, a function whose code is the following: dict['_if_'] = function () { var pif = parse_if( arguments[0] ); return (pif[0] === "true")? show_braces(pif[1]) : show_braces(pif[2]); }; Some little primitives should be enough to illustrate the principle: dict['*'] = function() { var args = arguments[0].split(' '); for (var r=1, i=0; i< args.length; i++) if (args[i] !== '') r *= args[i]; return r; }; dict['first'] = function () { var args = arguments[0].split(' '); return args[0]; } dict['rest'] = function () { var args = arguments[0].split(' '); return args.slice(1).join(' ');

} dict['='] = function() { var terms = arguments[0].split(' '); var a = parseFloat(terms[0]), b = parseFloat(terms[1]); return !(a < b) && !(b < a) }; dict['b'] = function () { return '< b>' + arguments[0] + '< /b>' }; The other can be seen in the alphawiki's meca/JS.js file.

3.9.......about evaluation speed In alphawiki, each page is edited and evaluated in real-time. The entire evaluation process is started again at each keyboard entry. Tested on a MacBook Pro (2GHz InterCore i7) in the FireFox browser, on a small set of alphawiki's pages, the evaluation's time related to the number of characters before and after the evaluation and to the number of braces {}, is detailed in the table below: page

chars before -> after

{}

time ms

1

start

16 532 -> 26 453

343

6

3

tutorial

15 931 -> 17 518

221

5

4

reference

18 557 -> 23 352

381

8

2

jules verne

1 230 422 -> 1 230 300

90

48

5

fibo_1

149 -> 52

12

10 000

6

fibo_2

200 -> 51

14

25

start, tutorial and reference are representative of wiki pages of an intermediate size equivalent to a 8/10 PDF pages, jules verne contains in a "pre-wrap" div a long text, a 300 pages book. 62 tags (h1, h2, h3) have been added to mark the chapter's titles and activate a TOC, fibo_1 and fibo_2 contain fibonacci functions. The first one is built on a naive recursive algorithm and puts the browser's engine on the knees after the 28th fibonacci number: 10.000ms. The second is built on a tail recursive algorithm and stays under 25 milliseconds when called for the 1000th fibonacci number. Beyond such a rather approximative benchmark, it appears that on a recent computer alphawiki++lambdatalk allows a comfortable realtime edition of standard pages found in a wiki.

4. ..... Conclusion This paper was intended to show some usages of lambdatalk and to give a quick view of its iconoclast underlying engine. As a conclusion, in the environment defined by alphawiki++lambdatalk working on top of any browser, the beginner, the webdesigner and the developer benefit from a simple text editor and a common language allowing, in a collaborative work, to build sets of complex and dynamic pages. The present paper has been created in alphawiki++, (average evaluation time: 11ms), and exported in PDF format (7 pages), directly from the browser, Firefox. alphawiki++ is free and under the GPL Licence.

5...... References [1] : Erick Gallesio and Manuel Serrano, http://www-sop.inria.fr /members/Manuel.Serrano/publi/jfp05/article.html#The-Skribeevaluator [2] : Matthew Flatt and Eli Barzilay, http://docs.racket-lang.org /scribble/ [3] : Kurt Nørmark, http://people.cs.aau.dk/~normark/laml/ [4] : Steven Levithan, http://blog.stevenlevithan.com/archives /reverse-recursive-pattern [5] : Alain Marty, http://epsilonwiki.free.fr/alphawiki_2/