Yet Another Wiki - epsilonwiki

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]);. } ...
3MB taille 0 téléchargements 322 vues
alpha +

SFPW_2014 :: oncemore

Yet Another Wiki Alain Marty Engineer Architect 66180, Villeneuve de la Raho, France [email protected] ABSTRACT « An environment where the markup, styling and scripting is all S-expression based would be nice. » would have said the father of LISP, John McCarthy [1]. It's the goal which was given to the lambdaway project: 1) build a small wiki environment, (alphawiki), and 2) define a small syntax, (lambdatalk), which allows markup, styling and scripting based on S-expressions.

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

1.......INTRODUCTION 1.1......The context Web browsers can parse data (HTML code, CSS rules, JS scripts, ...) stored on the server side and display rich multimedia dynamic pages on the client side. Some HTML functions, (texarea, input, form, ...) associated with script languages (PHP, Javascript, Regular Expressions, ...) allow interactions with these data leading to web applications like CMS (ie. blogs or wikis). 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 the markup and the styling but doesn't give any help on the scripting side. Works have been done to define a complete unified syntax, for instance: Skribe [5] 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 [6] 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 [7] 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: 1) as convenient as the SCHEME syntax has proven to be, it is unfitting for "easily" dealing with the textual content of a CMS (ie. a wiki), 2) these tools are definitively devoted to smart developers, not precisly to end-users or web-designers. It's the the lambdaway project's goal to give all of them a common

environment.

1.2......The lambdaway project Why such a project? What is the current state? Who is concerned?

1.2.1 ......why? 1) When Ward Cunningham [2] invented the concept of wiki in 1995, a kind of collective online text-editor, he had in mind the powerful functionalities of an amazing software created in 1987 for AppleInc by Bill Atkinson and Dan Winkler, HyperCard as the environment and HyperTalk as the language. Nowadays, there are many wiki engines well integrated in the browsers (the best known being Wikipedia) but the languages/syntaxes used for editing are far from being comparable to the HyperTalk powerful and user friendly language. 2) When Brendan Eich [3] created in 1995 the Javascript language to be integrated in the Netscape browser, he had in his mind the powerful functionalities of the LISP language created in 1958 by John Mc Carthy at MIT. But Javascript, which somebody consider as a LISP in C clothes, is working at the low level of the browser, the DOM, which is far from being comparable to the HyperCard nice and user friendly environment. The result is not actually the online HyperCard/HyperTalk that Ward Cunningham was dreaming of!

1.2.2 ......what? alphawiki is a small wiki coming with a small language, lambdaTalk: 1) alphawiki tries to fill the gap between the complex DOM and the end-user with a gentle interface similar to HyperCard's one : pages are cards with text containers, pictures and buttons. 2) lambdatalk fills the gap between the complex Javascript language and the user, with a simple and unified Lisp-like notation, used for creating rich texts, structured pages and dynamic content. 3) The couple alphawiki+lambdatalk intends to be an online HyperCard+HyperTalk, small, coherent and easy to use.

1.2.3 ......who? alphawiki is intended to be a tool for the writer, the designer and the coder, used in a collaborative work for creating and sharing on internet, complex chunks of rich, structured and dynamic data: 1) the writer is (supposed to be) an expert in his domain and brings information; with a reduced set of tags, he can easily fill pages with minimally structured and enriched informations (titles, paragraphs, lists, images, bold, italic, ...) 2) the designer strengths the information and gives it the best shape for the best communication; with the plain set of HTML/CSS functionalities, he can compose rich and sophisticated pages, 3) the coder extends the functionalities as needed; he can build new tools (a Table of Content, a worksheet, a paint or draw tool, math functions, a lisp console, ...) to be used by the writer and the designer. The three levels share the same language, lambdaTalk, in an easy learning curve smoothing the frontiers between the writer, the

designer and the coder.

1.3......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 Here we show how to write, style and code with lambdatalk.

2.1.......Writing some code An alphawiki++ website is made of several pages sharing the same appearance. Each page can be edited (by authorized users) via a frame editor, the result being evaluated and displayed in real-time in the wiki page. This is the "Hello World" example showing the linked frame editor and wiki page:

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 how this code is 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. John

Hello John ! We can see that a 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, leading to 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. In a standard text curly braces {} are much less frequent than round braces () and it's the reason they have been chosen for bracketing s-expressions. Note that, except for the value of HTML attributes following the standard HTML conventions, the texts are not surrounded by quotation marks or anything like that. This corrects the problem mentioned in the works recalled in the introduction.

2.2.......The evaluation process We will call leaf a terminal s-expression which doesn't contain any s-expression. The lambdatalk interpreter evaluates the nested s-expressions from the leaves 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 * and returns 3*4 = 12; {* 1 x} will return NaN because x is Not A Number, and when an s-expression is not evaluable, for instance {foo bar}, it will be returned unevaluated, just underlined, as it is: {foo bar}, without any error message polluting the wiki text!

2.3.......The dictionary The lambdatalk's core dictionary contains a list of words linked to some primitive functions. Writing {lib} displays: lib, serie, map, reduce, >, < , >=, lambda_6195 // OK, it's a function waiting for 2 values {boo 1} -> lambda_3262 // it's a function waiting for 1 value {boo 1 2} -> 3 // OK, it's called with two values {{boo 1} 2} -> 3 // OK, it's called in two steps {boo 1 2 3} -> 3 // OK, no matter with extra values As an application, writing derivees of any order is straightforward: {def D {lambda {:f :x} {/ {- {:f {+ :x 0.01}} {:f {- :x 0.01}} } 0.02} }} {def cubic {lambda {:x} {* :x :x :x}}} {cubic 2}} {{D cubic} 2}} {{D {D cubic}} 2}} {{D {D {D cubic}}} 2}} {{D {D {D {D cubic}}}} 2}}

-> -> -> -> ->

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

1) equation [1 -1 1] -> {equation 1 -1 1} 2) equation [1 -2 1] -> {equation 1 -2 1} 3) equation [1 1 -1] -> {equation 1 1 -1} displays:

It is good to compute once the value "s" used 4 times and we write:

{round {round {round {round {round

else {if {= :d 0} 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} {* }}

8 12 12 6 0

2.5.5.......quadratic equation In lambdatalk words and numbers can easily be mixed, without any string quotation or any special printing format. This is an example giving the roots of a 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}}

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 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 {@}}}} displays: numero radicand quotient quotient_line

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.......an application to web-design Remembering that in a wiki text and images are the main part of datas to organize, this is an example of what can be done with lambdatalk to mix texts, styles and numbers. {def postits {lambda {:n} {div {@data/amelie_sepia.jpg') no-repeat 100%50%; border:1px solid white; text-align:center; -webkit-transform:rotate(:ndeg); -moz-transform:rotate(:ndeg); transform:rotate(:ndeg); "}:n! = {factorial :n} }}} {map postits 1 2 3 4 5 6 7 8 9 8 7 6 5 4 3 2 1} The primitive function map calls the user function postits with a serie of numbers and displays:

:a0 :a1 :a2 :a3

:u :u :u :t

:u :u :t :t

:u :t :t :t

1} 3} 3} 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}} displays:

2.5.9.......the end user is not forgotten! Let's look at the first code shown at the beginning of this page. To make things easier for the beginner, lambdatalk comes with some "sugar" for blocks between line returns, ie. titles, paragraphs and lists: h1, p, ul, ol and for links: a. And with some help from a "smart coder" defining a couple of useful functions: {def blue span {@} }

2.5.8.......drawing in a wiki page Its possible to play with bezier curves, lambdatalk and CSS, without 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

{def hello-input {lambda {:hi} {input {@ type="text" placeholder="Please, enter your name" onkeyup="getId('yourName').innerHTML=' :hi '+this.value+' !'" }} {h1 {@ id="yourName"}} }}

this is how this code could be written by the end user: _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} with this result: 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

Bonjour Ward ! You may test the input field!

2.5.10.......plugins Lambdatalk can call more complex scripts stored in the "plugins" folder and executed interactively in the wiki page. For instance, it's possible to compute Ray Tracing, 3D shapes, fractals, ...

Spreadsheets are known to be a good illustration of the functional approach. It's possible to insert a spreadsheet in a wiki page and to make some calculus in it. For instance, the symbolic-expression {+ {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:

3.......LAMBDATALK INSIDE Here we will analyze the underlying Javascript engine. 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 PI quoting must be used: {quote PI} or 'PI. In the alphawiki context nothing is evaluated: the code is just text and not a sequence of symbols, (ie. sqrt), numbers, (ie. 123.45), or quoted strings, (ie. "Hello World"). Curly braces must be used to trigger the evaluation via s-expr.

3.1.......the evaluate() function Well formed s-expressions keyed in the frame editor are caught and evaluated by the evaluate() function. Unbalanced s-expressions lock the evaluation. The evaluation process of a leaf, a terminal S-expression, {first rest} is made in two stages: 1) a pre-processing phase and 2) a single loop. For some "special" values of first the s-expr evaluation is made in the pre-processing phase. For the others, leaves are first evaluated (ie. replaced by some text) in the loop until there is no more leaf. 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 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: 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.

2.6.......using lambdatalk: as a conclusion As a conclusion, lambdatalk is not a dialect of LISP and hasn't its powerful functionalities. But, with a dictionary of about a hundred primitive functions and a minimal set of three special forms, [lambda, def, if], lambdatalk opens the possibility of writing, styling and scripting web pages using a coherent and unique syntax. Numerous other usages of lambdatalk and several examples of its functionalities can be seen in the pages of alphawiki++.

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's applyed to to the rest array, if not the s-expression is returned unevaluated.

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

3.5.......evaluating lambdas The eval_lambdas() function catches every s-expressions {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. 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()*10000), 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 {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 : ''; }; Note that defs can be nested.

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 is known the value of the boolean term. 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 the then_term and the else_term are "deactivated" and the associated function _if_ belongs to the dictionary. During the s-expressions evaluation phase, this function will return the then_term or the else_term accoring 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 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 '{_if_ ' + bool_term + ' then ' + hide_braces(then_term) + ' else ' + hide_braces(else_term) + '}'; }; Note that ifs can be nested.

3.8.......some primitives in the dictionary The dictionary is an associative array: var dict = {}; Every elements of the dictionary have this structure : dict[ tag ] = function () { .. .. }; // coming from the function catch_sexprs(), // arguments come as a single element array, // so "var args = arguments[0]"

// gives arguments as a string // and "var args = arguments[0].split(' ')" // gives arguments as an array The if special form is closely related to the _if_ function belonging to the dictionary: dict['_if_'] = function () { var s = arguments[0], index1 = s.indexOf( 'then' ), index2 = s.indexOf( 'else' ), bool_term = s.substring(0,index1), then_term = s.substring(index1+5,index2), else_term = s.substring(index2+5); return (bool_term.trim() === "true")? show_braces(then_term.trim()) : show_braces(else_term.trim()); }; Following, just a few examples of primitive functions: 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['b'] = function () { return '< b>' + arguments[0] + '< /b>' }; More can be seen in the JS.js code.

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 heavy non tail-recursive functions may require more CPU time. The natural structure of a wiki, a stack of cards, helps to limit the load to a bearable value.

4. ..... CONCLUSION This paper was intended to show some usages of lambdatalk and a quick view of its underlying engine. More can be seen in the alphawiki++ website : http://epsilonwiki.free.fr/alphawiki_2/. 1) The lambdatalk syntax is small, simple and easy to be used by any beginner and any web-designer. 2) The underlying JS code is small, simple and easy to be mastered by any JS developer. 3) The underlying JS code appears to be fast enough to be usable in the context of webdesign, and powerful enough to follow some more complex developer's experimentations. With alphawiki++lambdatalk, the beginner, the web-designer and the developer benefit from a simple text editor and a common syntax allowing them, in a gentle learning slope and a collaborative work, to build sets of complex and dynamic pages. alphawiki++ is free, under the GNU Copyleft Licence. This paper has been built in alphawiki++ and exported as A4 PDF A4 format directly from the browser (Firefox).

5...... REFERENCES [1] : John McCarthy, http://www-formal.stanford.edu/jmc/ [2] : Ward Cunningham, http://c2.com/~ward/ [3] : Brendan Eich, https://brendaneich.com/ [4] : Steven Levithan, http://blog.stevenlevithan.com/ [5] : Erick Gallesio and Manuel Serrano, http://www-sop.inria.fr /members/Manuel.Serrano/publi/jfp05/article.html#The-Skribeevaluator [6] : Matthew Flatt and Eli Barzilay, http://docs.racket-lang.org /scribble/ [7] : Kurt Nørmark, http://people.cs.aau.dk/~normark/laml/ [8] : Alain Marty, http://epsilonwiki.free.fr/alphawiki_2/