SFPW_2014 :: YAW_20140910Yet Another Wiki - epsilonwiki

Sep 10, 2014 - documents in HTML or PDF (via Latex) form. Scribble helps ... programmer use the power of abstraction and programmed solutions when he or she is .... word bound to a value without calling its value. Such a behaviour is.
2MB taille 1 téléchargements 277 vues
+

SFPW_2014 :: YAW_20140910Yet

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 webdesigners (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

smart developers and not to webdesigners and even less to beginners. It is 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 internet hosting service. It is mainly built on two files: 1) PHP.php: on the server side a 500 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 choices.

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, the code is evaluated and displayed in real-time. This is an example illustrating the linked frame editor and wiki page:

1.1......The context Web browsers parse data such as HTML code, CSS rules and Javascript code 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 MediaWiki, Wordpress, 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 & 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 looks familiar to anyone used to markup languages.», Scribble [2] by Matthew Flatt & 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 ». With the plain benefit of existing Scheme implementations, these projects make a strong junction between the markup, styling and programming syntaxes. But these tools are definitively devoted to

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 [3,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"}} and its evaluation 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 [3,4] is equal to 5. 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 "href" 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 familiar to a webdesigner, and acceptable to the beginner.

2.2.......The evaluation process lambdatalk evaluates nested S-expressions, {first rest}, from the leaves - the terminal S-expressions without any inside S-expression - to the root. The evaluation process is the application to the arguments contained in rest of a function belonging to the dictionary and linked to first. 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, contrary to the three projects pointed out before, in {u Hello World}, Hello World is not quoted. In lambdatalk strings must not be escaped by quotation marks or anything else. It can be considered as an essential capability 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 >, < , >=, [0.123 0.456] {first {V}} -> 0.123 // but we can get {rest {V}} -> 0.456 // its members {length {V}} -> 2 // the dimension of V {def V.norm {lambda {:v} {sqrt {+ {* {first {:v}} {first {:v}}} {* {rest {:v}} {rest {:v}}}}}}} -> V.norm {V.norm V} -> 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. Actually, 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 {< 11 12} then {+ 1 0} else {/ 1 0}} will not evaluate the unused division by zero in the else_term, and will safely return the value of the then_term, 1. This fundamental lazy behaviour avoids unnecessary and/or dangerous evaluations and opens the way to recursive functions.

2.5.......coding lambdatalk

else {* :n {fac {- :n 1}}}}}} -> fac {fac 6} -> 720 2) Thanks to nestable defs, this is 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}}} -> ifac {ifac 21} -> 51090942171709440000 3) And a last one without any def, a taste of Y-combinator: {{lambda {:f :n} {:f :f :n}} {lambda {:f :n} {if {= :n 1} then 1 else {* :n {:f :f {- :n 1}}}}} 6} -> 720

2.5.2.......loops Thanks to recursion loop structures can be built. For instance, 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 constants and functions are in the global scope, limited to the wiki page. Lisp and its dialects have a let special forms to define local values. Actually, in Lisp, the let special form is nothing but a sugar built on 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 In order to compute once the value s used 4 times we will 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

The three special forms [lambda, def, if] are the necessary an sufficient conditions for lambdatalk to reach the level of a programmable programming language. Actually, lambdatalk comes with a fourth special form, {q some text} allowing to quote S-expressions as in standard Lisp dialects. We will forget it in this paper and focus on some usages of the lambdatalk functionalities.

where the fourth argument of the internal lambda :s is used as a local variable.

2.5.1.......recursion

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

lambdatalk accepts recursive functions. Let's consider three versions of the factorial function. 1) The basic version following the mathematical definition: {def fac {lambda {:n} {if {< :n 1} then 1

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:

{boo} -> lambda_6195 // this is a function waiting for 2 values {boo 1} -> lambda_3262 // this is now a function waiting for 1 value {boo 1 2} -> 3 // called with two values it returns a value {{boo 1} 2} -> 3

// called in two steps it returns a value {boo 1 2 3} -> 3 // the extra value is ignored Thus, it is straightforward to 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.......cons, car, cdr lambdatalk doesn't work on structured lists and doesn't know pairs. The [cons, car, cdr] functions are not included in the lambdatalk's dictionary. But, nevertheless, it is possible to define these as user functions, according to the workaround shown in Structure and Interpretation of Computer Programs [5]. As an illustration of this capability we will give a much better alternative to the 2DVectors definition given in a previous section "2.4.2.3 non scalar constants". For this purpose, we will replace [cons, car, cdr] by more adapted ones: [V.make, V.x, V.y] and we will define two additional functions V.print & V.add: {def V.make {lambda {:x :y :f} {if :f then :x else :y}}} -> V.make {def V.x {lambda {:z} {:z true}}} -> V.x {def V.y {lambda {:z} {:z false}}} -> V.y {def V.print {lambda {:z} [{V.x :z},{V.y :z}]}} -> V.print {def V.add {lambda {:v1 :v2} {V.make {+ {V.x :v1} {V.x :v2}} {+ {V.y :v1} {V.y :v2}}}}} -> V.add We can now create 2DVectors and concatenate add operations: {V.print {V.make 0.123 0.456}} -> [0.123,0.456] {V.x {V.make 0.123 0.456}} -> 0.123 {V.y {V.make 0.123 0.456}} -> 0.456 {V.print {V.add {V.add {V.add {V.make 1 0} {V.make 0 1}} {V.make -1 0}} {V.make 0 -1}}} -> [0,0] The alphawiki++ website gives examples of more Vector operations (norm, dot, cross) and some applications to polynomials, complex numbers, rational numbers, and so on.

2.5.6.......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 discriminant = :d {if {> :d 0} then 2 real roots : x1 = {/ {- {- :b} x2 = {/ {+ {- :b} else {if {= :d 0}

:d}

{sqrt :d}} {* 2 :a}} {sqrt :d}} {* 2 :a}} then

1 double real root : x = {/ {- :b} {* 2 :a}} else 2 complex roots : x1 = [{/ {- :b} {* 2 :a}} -{/ {sqrt {x2 = [{/ {- :b} {* 2 :a}} +{/ {sqrt {}} } :a :b :c {+ {* :b :b} {* }}

, :d}} {* 2 :a}}] , :d}} {* 2 :a}}] 4 :a :c}}}

{b 1) equation [1 -1 1]} -> {equation 1 -1 1} {b 2) equation [1 -2 1]} -> {equation 1 -2 1} {b 3) 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 : x1 = [-0.5 , -0.8660254037844386] x2 = [-0.5 , +0.8660254037844386]

2.5.7......mathematical notations As long as the mathML tags won't be recognized by Chrome, lambdatalk can be a useful substitute to display some mathematics. {def numero {lambda {:n} {div {@}:n}}} {def radicand {@}} {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.8.......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}} will display these two cubic curves anywhere in the wiki page:

Spreadsheets are known to be a good illustration of the functional approach. With lambdatalk it is 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:

If alphawiki can be considered as a stack of pages, in the same way, an embedded spreadsheet 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 is 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 is 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

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

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 them [if,lambda,def], the evaluation is made in the pre-processing phase. For the others, the 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. According to the values of first and rest, this evaluation is made in a unique global environment, named dictionary. 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 -

currying and functions composition. 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(' '); 3.3.......evaluating S-expressions return function (bod) { if (vals.length < args.length) { Following a code snippet shared by Steven Levithan [4], the for (var i=0; i < vals.length; i++) eval_sexprs() function is a one line single loop using the bod = bod.replace(reg_args[i],vals[i]); previous Regular Expression to catch S-expressions and the var _args = do_apply() function to replace them by their value: args.slice(vals.length).join(' '); bod = eval_lambdas( var eval_sexprs = function(str) { '{lambda {'+_args+'}'+bod+'}'); while } else if (vals.length==args.length) { (str != (str=str.replace(loop_rex,do_apply))); for (var i=0; i < vals.length; i++) return str; bod = bod.replace(reg_args[i],vals[i]); }; } else { // vals.length > args.length for (var i=0; i < args.length; i++) var do_apply = function() { bod = bod.replace(reg_args[i],vals[i]); var first = arguments[1] || '', } rest = arguments[2] || ''; return bod; if (dict.hasOwnProperty(first)) }(body); return dict[first].apply(null, [rest]); }; else return name; return hide_braces( }; '< u>{' + first + ' ' + rest + '}< /u>'); };

3.6.......evaluating defs

If first belongs to the dictionary it is applied to rest and the value is returned. If not the S-expression is returned unevaluated.

The eval_def() function catches every S-expressions having this shape {def name body} and replaces it by the given name.

3.4.......evaluating special forms

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; };

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 each S-expression having this shape {lambda {:args} body} and replaces it by a random name. This name is associated with a function which, when it will be called, will replace in the body the arguments' occurrences by the given values. Prefixing arguments names by a distinctive character, ie. a colon, is mandatory to avoid any conflict in the replacement process. The function handles the difference of numbers between arguments and values, allowing partial calls,

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 in relation to the bool_term's value. 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 (eval_sexprs(pif[0]) === "true")? eval_sexprs(show_braces(pif[1])) : eval_sexprs(show_braces(pif[2])); }; To finish, this is the detail of some simple primitives: 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>' }; Other primitives 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 stops the browser's engine 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 underlying engine. As a conclusion, in an 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 a collaborative creation of dynamic web pages sets. The present paper has been created in alphawiki++ - the average evaluation time being around 11ms - and exported in 7 pages PDF format directly from the browser, Firefox. alphawiki++ is free and under the GPL Licence, @ http://epsilonwiki.free.fr/alphawiki_2/ .

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] : H.Abelson and GJ.Sussman, SCIP, http://mitpress.mit.edu /sicp/full-text/book/book-Z-H-14.html#%_sec_2.1.1