return page history
α-wwwiki
::
history/lambdaway/20131021-213156.txt
editor : alpha [82.250.155.62] 2013/10/21 21:31:56 {center {i Would you like an english translation ? Ask me in the [[forum]] !}} {div {@ style=" position:absolute; top:-20px; left:400px; font:bold 5em times; color:red; text-shadow:0 0 8px black; z-index:1; "} °°{λy}°° } {div {@ style="display:none;"} {define cod () °° var args = [].slice.call(arguments).join( ' ' ); var style= "font:normal 0.8em arial;" +"background:#888;" +"color:#fff;" +"text-align:center;" +"padding:0 10px;" +"border:1px solid;" +"box-shadow:0px 0px 2px black;" +"-webkit-border-radius:10px;" +"-moz-border-radius:10px;" +"border-radius:10px;"; return '{span {@ style="' + style + '"}' + args + '}'; °°} } _h1 évaluateur ? _p Evaluer une S-expression dans le cadre d'un dictionnaire pré-défini est une chose assez simple, cf pages [[evaluation]] et [[yaw]]. Cela se complique lorsque certains de ses termes ne sont pas connus au moment de l'écriture. C'est à ce moment-là qu'interviennent les opérateurs {cod if}, {cod lambda} et {cod def}, et que le dictionnaire se met à grossir. On entre alors dans le domaine du codage ... _h3 1. S-expression _p L'évaluation d'une S-expression {cod °°{first rest}°°} consiste en l'application de l'opérateur {cod first} aux arguments contenus dans {cod rest}. Le terme {cod first} est un nom de fonction ou une S-expression produisant un nom de fonction, {cod rest} est une chaîne de mots (suite de caractères sans espace), de nombres (au sens où ils sont compris par l'environnement) et de S- expressions. _p Classiquement, l'évaluation se fait suivant le modèle récursif {b evaluate(build_nested_array(tokenize( string )))}, cf par exemple [[lisp_evaluator]]. En ce qui concerne [[lambdatalk|?view=lambdatalk]] destiné à être embarqué dans un wiki, un autre modèle plus adapté à ce contexte est choisi. Il est basé sur {b une seule boucle appliquant une unique expression régulière} et l'évaluation se fait en commençant par les S-expressions terminales (ne contenant aucune S-expression) jusqu'à la S-expression englobante. C'est ce modèle qui servira de fond aux considérations qui suivent. _h3 2. évaluation immédiate : {span {@ style="color:red;"}dico} _p Tout est pour le mieux quand tous les termes d'une S-expression ont une valeur connue. Par exemple, dans l'expression {cod °°{+ 1 2}°°} le symbole {cod +} appartient au dictionnaire de fonctions prédéfinies, {cod 1 et 2} sont deux symboles reconnus comme étant des nombres et évalués à eux-mêmes. L'appel de la fonction avec les deux arguments {cod 1 et 2} produira donc la valeur {cod 3}. Toute calculatrice sait faire cela ! _h3 3. évaluation contrôlée : {span {@ style="color:red;"}if} _p Il est parfois nécessaire d'Introduire des branchements dans le processus d'évaluation. On définit l'opérateur spécial {b if} : {cod °°{if bool then then_term else else_term}°°}, où {b bool} est une valeur booléenne (true ou false), pouvant être le résultat de l'évaluation d'une S-expression utilisant des opérateurs booléens prédéfinis {cod = < > <= >= not or and} et qui provoquera l'évaluation de l'un des deux termes {b then_term} ou {b else_term}. Exemples: _ul {cod °°{if {< 1 2} then {/ 1 2} else {/ 1 0}}°° -> -0.5} : OK !! _ul {cod °°{if {> 1 2} then {/ 1 2} else {/ 1 0}}°° -> Infinity} : oops !!! _p Dans les deux cas précédents tous les termes sont connus et, suivant ce qui a été vu plus haut, les 4 S-expressions (oui 4 !) devraient être évaluées. Mais même dans le premier cas, la division par zéro contenue dans le second {b else_term} génèrerait une erreur et bloquerait probablement l'évaluation. En fait, l'évaluation des termes d'une S-expression {b if} {u doit être reportée}, seul le terme associé à la valeur du booléen sera évalué, et l'autre sera simplement "oublié". La section {b 6.} en montre une application importante. _h3 4. évaluation différée : {span {@ style="color:red;"}lambda} _p L'expression {cod °°{+ a b}°°} contient deux symboles {cod a et b}, qui ne sont ni des nombres ni des S-expressions. Leur valeur n'est pas connue au moment de l'écriture de la S-expression et son évaluation {u doit être reportée}. On la mémorise dans le dictionnaire sous la forme d'une fonction (un enclos, une fermeture, une lambda, une liaison) associant à tous les termes {cod a et b} contenus dans le corps les valeurs qui seront fournies à l'appel de la fonction, par exemple les valeurs {cod 1 et 2}. _p On définit pour cela l'opérateur spécial {b lambda}. L'expression {cod °° {lambda {:a :b} {+ :a :b} °°} crée cette fonction en lui attribuant un nom aléatoire, du type {cod lambda_12345}, inconnu en principe de l'utilisateur, une fonction anonyme. L'expression {cod °°{lambda_12345 1 2}°°} produirait ainsi la valeur {cod 3}. Dans la mesure où le nom est inconnu, on couple en réalité la définition et l'appel : {cod °° {{lambda {:a :b} {+ :a :b} 1 2} -> 3°°}. Et la fonction anonyme retourne ensuite dans les limbes du "garbage collector". _h3 5. extension du dictionnaire : {span {@ style="color:red;"}def} _p On aimerait conserver plus longtemps cette fonction, ne serait-ce que pour pouvoir l'utiliser plusieurs fois sans avoir à écrire sa définition. De façon plus pratique on découplera souvent la définition et l'appel de la fonction en lui donnant un nom. On définit pour cela l'opérateur spécial {b def}. L'expression {cod °°{def add {lambda {:a :b} {+ :a :b}}°°} associera le nom {cod add} à la définition de la fonction. Et ceci de façon permanente : l'expression {cod °° {add 1 2}°°} produira {cod 3}, {cod °°{add 3 4}°°} produira {cod 7}, et ainsi de suite. _p De façon générale, {cod °°{def nom expression}°°} associe un nom à une S-expression, augmentant ainsi le dictionnaire des fonctions pré-définies. Si l'expression ne contient que des termes évaluables, par exemple {cod °°{def myPI 3.1416} -> 3.1416°°} ou {cod °°{def 2PI {* 2 {PI}}°° -> 6.283185307179586} elle est évaluée et mémorisée sous forme de constante. Sinon, elle est mémorisée à l'aide de l'opérateur {cod lambda} sous la forme d'une fonction dont l'appel fournira les valeurs manquantes. _h3 6. application : {span {@ style="color:red;"}recursion} _p Les 3 opérateurs "spéciaux" {cod if, lambda, def} n'appartiennent pas au dictionnaire de base, ils doivent être traités avant l'évaluation proprement dite afin de désactiver les S-expressions imbriquées et retarder ainsi leur évaluation au moment opportun. _p Ces trois opérateurs ouvrent la voie aux codes récursifs et aux boucles, et donc au codage de tous les programmes imaginables. Le cas d'école d'un tel code est celui de la fonction factorielle {b n!}. On la définit ainsi : {b n! est le produit des nombres entiers de 1 à n}. Et pour que l'évaluateur puisse faire quelque chose de cette belle phrase, on écrit un algorithme récursif : {b si n est nul alors n! = 1 sinon n! = n*(n-1)}. Avec l'aide des opérateurs def, lambda et if on écrira : _ul {cod °° {def ! {lambda {n} {if {< n 1} then 1 else {* n {! {- n 1}}}}}} -> ! °°} _p ou de façon plus lisible : {pre °° {def ! {lambda {n} {if {< n 1} then 1 else {* n {! {- n 1}}} } } } °°} _p Une fois ajoutée au dictionnaire, cette nouvelle fonction {cod !} pourra être appelée comme n'importe quelle fonction primitive autant de fois que souhaité : _ul {cod 6! = °° {! 6} -> 720 °°} _ul {cod 20! = °° {! 20} -> 2432902008176640000 °°} _p Dans un langage ne connaissant pas la récursion on écrirait une boucle : {pre °° function fac (n) { var result = n; for (var i = n-1; i > 1; i = i-1) { result = result * i; } return result; } fac( 6 ) -> 720 °°} _p On notera au passage la multiplication des notations dans cette syntaxe et l'introduction de variables annexes (result et i). Avec la récursion, les boucles deviennent possibles sans faire appel au concept de compteur, sans faire appel au concept d'affectation et de mutation de variable. On est dans la programmation fonctionnelle où les fonctions retournent toujours la même valeur, sans effet de bord. A moins qu'on définisse un nouvel opérateur {cod set!}, mais ceci est une autre histoire ! _h3 7. coder _p Ecrire et éxécuter un programme, c'est créer un ensemble de fonctions inter-agissant sur un ensemble de données et appeler la fonction {b maître} qui les exécutera. Les langages courants (Pascal, C, C++, Java, Python, Ruby, ...) disposent de syntaxes plus ou moins complexes faisant toujours une nette différence entre les données et les fonctions qui les traitent. Dans le cas d'un évaluateur de S-expressions, on notera la similitude des notations entre les opérateurs et les données. C'est le point commun des dialectes du {b LISP} défini en 1960 sur un nombre très réduit de {cod 5 ou 7} formes primitives capables de générer tous les codes imaginables. « Les Equations de Maxwell de l'Informatique », comme le disait le père de SmallTalk, Alan Kay. _p Mon dernier évaluateur en date, [[lambdatalk|data/lambdatalk/]], s'appuie sur les principes minimalistes du LISP (sans tenter d'en être un nième dialecte comme [[alphalisp|?view=lisp_evaluator]]), et bénéficie de la fondation confortable des navigateurs WEB et de leurs langages intégrés, le HTML, le CSS, et le LISP habillé en C malencontreusement appelé JavaScript. Lambdatalk dispose ainsi "gratuitement" de {b 50} opérateurs HTML, des {b 30} fonctions mathématiques intégrées dans le JavaScript, et ajoute à cette base solide {b 20} nouveaux opérateurs et les {b 3} formes spéciales indispensables {cod if, lambda, def} permettant d'en créer de nouveaux. Associé au moteur PHP d'alphawiki qui assure les fonctions de lecture et d'écriture sur le WEB, le [[code de lambdatalk|data/lambdatalk/lambdatalk.js]], réduit à très peu de lignes (une centaine pour l'évaluateur, environ quatre cent pour le dictionnaire pré-défini), semble se révèler suffisant pour autoriser dans des conditions confortables la composition et le codage de pages multimedia interactives et complexes. Au moins autant que l'ancêtre [[epsilonwiki|../]] et le présent [[alphawiki|?view=start]]. Qu'en pensez-vous ? _p N'hésitez pas à tester la [[console lambdatalk|data/lambdatalk/]] et à me donner votre avis dans le [[forum]]. _p alain marty 21/10/2013 {hr} _p {b remarque :} à la relecture, malgré tous mes efforts, je dois constater que tout ceci n'est pas bien clair, ça se mélange un peu et ça manque de rigueur. Du travail en perspective ...