SFPW_2014 :: YAW_20140828Yet Another Wiki - epsilonwiki

Aug 29, 2014 - capabilities of a true programmable programming language. User functions can be created ... lambdatalk will be progressively introduced, starting as a simple. S-expressions ... documents in HTML or PDF (via Latex) form. Scribble helps to ... sqrt is a math function computing the square root of a number,.
2MB taille 3 téléchargements 268 vues
+

SFPW_2014 :: YAW_20140828Yet

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 single loop working on a unique Regular Expression and a small dictionary of hundred primitive functions, lambdatalk provides a coherent S-expression based notation to write and style text in a wiki. Then, thanks to a minimal set of 3 special forms, [lambda, def, if], lambdatalk offers the capabilities of a true programmable programming language. User functions can be created extending the dictionary, functions are first class citizens, they can be recursive and used to build loops and structured datas like arrays, vectors, polynoms. The present paper will focus on lambdatalk. In a first section, lambdatalk will be progressively introduced, starting as a simple S-expressions evaluator to reach the level of a programmable programming language. Then will be detailed the RegExps based underlying engine, in order to explain why such an "iconoclast" choice, forgetting the standard mechanism popularised by LISP and its dialects, could be seen as an acceptable answer in a wiki context devoted to users coming from different horizons.

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

1.......Introduction

styling and programming syntaxes. But these tools are definitively devoted to smart developers and not precisly to beginners and webdesigners. alphawiki and its language, lambdatalk, have been conceived to give them a simplified common environment.

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 shown writing, styling and coding in lambdatalk. in "3. Lambdatalk inside" will be quickly analyzed the lambdatalk underlying Javascript engine.

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:

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 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, Wikipedia, Joomla,.... The de facto standard Markdown syntax is widely used to simplify and unify markup and styling but can't be used 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,

Consider a more complex 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. Ward Cunningham

Hello Ward Cunningham ! 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 math 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, giving to them a tree structure. 3) first and rest are framed between an opening and a closing curly braces, {}, acting as escape characters launching the evaluation process. Being much less used in a standard text than round braces, (), curly braces have been chosen for bracketing s-expressions.

2.2.......The evaluation process

note_start, note_end, back, post, drag, listing, show, lightbox, forum, editable, require, lisp, lc, sheet In these hundred functions can be recognized some words used in the previous example: HTML tags with their attributes and CSS rules, Javascript's Math object functions, and new ones created for alphawiki. With this rather small set of primitives called via a coherent and unified syntax, wiki pages can be built using all the whistles and bells of HTML and CSS syntaxes and the power of the Javascript language (with some restrictions for security). But until now, we can't find any word, any function to compute, for instance, the hypotenuse of a right triangle whose sides are a and b, where a and b have not yet assigned numerical value! In the following section we will extend the dictionary with such a function and more others.

2.4.......Extending the dictionary In order to make possible the creation of such new user functions, lambdatalk comes with three new special words, called special forms, [lambda, def, if].

2.4.1.......user functions (lambda) The special form lambda is used to create local bindings. Writing: {{lambda {:a :b} {sqrt {+ {* :a :a} {* :b :b}}}} 3 4} binds :a to 3 and :b to 4 and returns 5. In fact: {lambda {:a :b} {sqrt {+ {* :a :a} {* :b :b}}}} doesn't evaluate its inner s-expressions and returns a random name, say lambda_1234. This function's name can't be used outside the local binding and such a function is called anonymous.

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!

2.4.2.......names (def)

2.3.......The dictionary

{hypo 3 4} -> 5 {hypo 1 1} -> 1.4142135623730951

The lambdatalk's core dictionary contains a list of words linked to some primitive functions. Writing {lib} displays: lib, serie, map, reduce, >, < , >=, PHI {PHI} -> 1.618033988749895 Complex bunches of CSS rules can be called by a simple name: {def blue_georgia span {@}} {{blue_georgia} Blue Georgia} which displays:

Blue Georgia 2.4.2.3.......non scalar constants The non standard behaviour of constants in lambdatalk makes possible an easy 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. But for now, we will focus on two fundamental numbers allowing us to write conditional s-expressions and some alternatives in the evaluation process.

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 {not false} -> true {or {< 11 12} {> 11 12}} -> true {and {< 11 12} {> 11 12}} -> false {if {< 11 12} then YES else NO} -> YES ... and so on 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 lambdas can be nested, and it's easy to write a version using tail recursion: {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 is good 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: {def boo {lambda {:a :b} {+ :a :b}}} -> boo {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 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} }} {def cubic {lambda {:x} {* :x :x :x}}} {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 : x1 = [-0.5 , -0.8660254037844386] x2 = [-0.5 , +0.8660254037844386]

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

2.5.6.1 defining some specific functions {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 {@}}}}

2.5.6.2 using these functions to display formulas 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}}

_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.

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:

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. As a first conclusion, with a dictionary of about a hundred primitive functions and a minimal set of three special forms, [lambda, def, if], we have seen that lambdatalk allows writing, styling and scripting in a unique, coherent and readable syntax. The underlying engine of lambdatalk is now introduced in the following section.

3.......Lambdatalk inside Lambdatalk is not a Lisp dialect and the evaluation process is quite different. In a Lisp console, everything is evaluated: for instance the word PI would be evaluated to its value, 3.141592653589793. In order to prevent the evaluation of an S-expression quoting must be used, for instance: {quote PI} or 'PI. In the alphawiki context nothing is evaluated: the code is just text and not a sequence of symbols, numbers or quoted strings, (ie. "Hello World"). Curly braces must be used to trigger the evaluation via s-expressions.

3.1.......the evaluate() function Well formed s-expressions are caught and evaluated by the

evaluate() function. The evaluation process of an s-expression {first rest} is made in two stages: 1) a pre-processing phase and 2) the main single loop. For some "special" values of first the evaluation is made in the pre-processing phase. For the others, leaves (terminal s-expressions) are first evaluated in the loop until there is no more s-expression. The evaluation of a leaf {first rest} is made in a 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 -

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

3.6.......evaluating defs The eval_def() function catches every s-expressions having this shape {def name body} and replaces it by the given name. 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 ); 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 : ''; };

return (pif[0] === "true")? show_braces(pif[1]) : show_braces(pif[2]); }; Here is a short abstract of the dictionary: 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; };

Note that defs can be nested but aren't local to the outside def.

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 the s-expression {_if_ bool_term then then_term else else_term} where _if_ is an associated function belonging to the dictionary 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); 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]; }; Note that ifs can be nested.

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] );

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['b'] = function () { return '< b>' + arguments[0] + '< /b>' }; More can be seen in the JS.js file.

3.9.......about evaluation speed alphawiki++lambdatalk allows a rather comfortable realtime edition of a standard page. Tested on a MacBook Air: Pages's content in chars

Speed

1

A page containing about 5,000 chars

1 to 2 ms

3

Pages between 20,000 and 50,000 chars

5 to 15 ms

A very heavy test page "Jules Verne, Ile mystérieuse" built on a plain text of 2 1,228,778 chars with a TOC of 62 chapters (about 15 360 lines = 300 pages of 50 lines)

about 70 ms

It's evident that the nature of the content of a wiki page has a great influence on the evaluation speed. Calling a little non tail-recursive fibonacci function can easily require musch more CPU time than the evaluation of a plain text containing a million words.

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, with alphawiki++lambdatalk, the beginner, the web-designer 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++ and exported as a PDF format directly from the browser (Firefox). alphawiki++ is free, 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/