lambdaway
::
reflexions_20201219
5
|
list
|
login
|
load
|
|
_img data/person-thinking.jpg {center {i ze '{lambda way}, kézako ?}} _h1 ... | [[meta8]] | french | [[digest]] _p Bon, le projet '{lambda way} ça ne passe pas chez monsieur et madame ToutleMonde qui n'en a rien à faire des lambdas, étant donné que Gmail, FaceBook, WhatsApp, Instagram suffisent complètement à leur quotidien. Et ça ne passe pas davantage chez les savants en informatique qui ont une fois pour toutes décidé que ce vieux lambda-calcul était réservé aux docteurs, qui considèrent que '{lambda way} est à l'évidence tout juste bon à faire de jolies pages web et ne trouvera jamais un quelconque public. _p Je peux comprendre l'indifférence que récolte le projet '{lambda way}, j'ai moi-même du mal à le classer. Alors, laissons de côté le wiki '{lambda tank}, un environnement de travail sur le web qui reste une ébauche d'un {b Content Management System} très spartiate et ne parlons que de '{lambda talk}, le langage. Il me semble en effet que '{lambda talk} présente au moins l'intérêt d'être une introduction simple et rapide aux points clés d'un langage de programmation. Sans rire. Laissez-moi tenter de le démontrer. _h2 plan _ul 1) substitution de texte _ul 2) les alias _ul 3) les fondations _ul20 3.1) les booléens, tests _ul20 3.2) les paires, listes _ul20 3.3) les boucles, récursion _ul 4) les sucres syntaxiques _ul20 4.1) if _ul20 4.4) let _ul 5) les primitives _ul 6) les bibliothèques _h2 1) substitution de texte _p L'aventure commence avec un simple utilitaire de remplacement de texte comme ceux qui équipent tous les éditeurs de texte. Il me semble que l'expression qui suit peut être comprise par tout le monde : {pre remplace : x et y dans : Mon prénom est x et mon nom y. par : James Bond } _p Je veux croire que n'importe qui peut prévoir ce résultat : {pre Mon prénom est James et mon nom Bond. } _p où les caractères {b x} et {b y} ont été remplacés par les mots {b James} et {b Bons}. Si ce n'est pas le cas, le mieux est d'arrêter là la lecture de ce papier. Sinon on peut continuer et comprendre que cette assez étrange écriture "codée", {pre '{{lambda {x y} Mon prénom est x et mon nom y. } James Bond} } _p en est une forme équivalente où le mot {b remplace} a été remplacé par {b lambda} et les mots {b et, dans, par} ont été remplacés par quelques parenthèses appairées bien placées. Simples raisons historiques pour {b lambda} en référence au {b λ-calcul} inventé dans les années trente par un mathématicien, Alonzo Church. Quant aux accolades, il suffit de savoir qu'elles permettent de construire de profondes structures imbriqués dont l'évaluation peut être automatisée. Ce codage premet de gagner beaucoup en concision, lecture et écriture, une qualité qui ouvre la voie à des algorithmes d'une complexité insoupçonnée. _p Poursuivons avec un peu d'arithmétique, une opération très simple, {i additionner les nombres 1 et 2}. Attention, voici le code : {pre '{{lambda {a b} {+ a b} } 1 2} -> {{lambda {a b} {+ a b} } 1 2} } _p On a bien compris que les nombres {b 1} et {b 2} remplacent {b a} et {b b} dans l'expression {b '{+ a b}}, conduisant à {b '{+ 1 2}}, une expression qui peut se lire ainsi "{b additionne 1 et 2}" dont on imagine que le résultat est {b 3}. Améliorons un peu cette expression {pre '{{lambda {a b} la somme de a et b est égale à {+ a b} } 1 2} -> {{lambda {a b} la somme de a et b est égale à {+ a b} } 1 2} } _p Mais là il y a un problème ! Le voyez-vous ? Toutes les occurences de {b a} ont été remplacées par {b 1} et ce n'est évidemment pas ce que nous voulons. Voici une écriture qui fonctionne : {pre '{{lambda {:a :b} la somme de :a et :b est égale à {+ :a :b} } 1 2} -> {{lambda {:a :b} la somme de :a et :b est égale à {+ :a :b} } 1 2} } _p On comprend que préfixer la "variable" {b a} avec un caractère d'échappement, par exemple les deux points ":", a eu pour effet de bloquer son remplacement par la valeur {b 1} dans les mots {b la} et {b égale}. C'est la convention que nous suivrons {b systématiquement} pour la suite : {i toujours préfixer les "variables" avec un caractère d'échappement}. _p C'est le moment d'introduire les {b alias}. _h2 2) les alias _p En écrivant {pre '{def HI hello brave new world} -> {def HI hello brave new world} } _p on associe au mot {b HI} la phrase {b hello brave new world}. Et il suffira d'encadrer ce mot de deux accolades pour retrouver la valeur associée : {pre '{HI} -> {HI} } _p Voilà donc une fonctionnalité intéressante qui nous permet de créer des {b constantes} qui seront utilisables autant de fois que nécessaire n'importe où dans la page wiki. N'importe quelle expression peut être ainsi {b nommée}, par exemple la formule du nombre d'or : {pre '{def φ {/ {+ 1 {sqrt 5}} 2}} // φ = (1+√5)/2 -> {def φ {/ {+ 1 {sqrt 5}} 2}} '{φ} -> {φ} } _p Dans le même esprit nommons {b swap} - {i échange in english} - l'expression parenthésée interne à la première expression que nous avons abordée, après avoir supprimé le "bla bla bla" : {pre '{{lambda {:a :b} :b :a } hello world} -> {{lambda {:a :b} :b :a} hello world} devient '{def swap {lambda {:a :b} :b :a} } -> {def swap {lambda {:a :b} :b :a}} suivie par '{swap hello world} -> {swap hello world} } _p Et enfin nommons {b smart_add} l'expression parenthésée interne à la seconde expression de remplacement améliorée vue plus haut {pre '{{lambda {:a :b} la somme de :a et :b est égale à {+ :a :b} } 1 2} devient '{def smart_add {lambda {:a :b} la somme de :a et :b est égale à {+ :a :b} }} -> {def smart_add {lambda {:a :b} la somme de :a et :b est égale à {+ :a :b} }} suive par '{smart_add 1 2} -> {smart_add 1 2} } _p une fonction que l’on a tout de suite envie d'appliquer à d'autres valeurs, par exemple : {pre '{smart_add 3 4} -> {smart_add 3 4} } _p Nous venons de créer deux nouveaux opérateurs, {b swap} et {b smart_add}, étendant les primitives supposées pré-définies dans le dictionnaire du langage, comme l'opérateur {b +}. Et chemin faisant on a abordé les premiers éléments constitutifs d'un langage de programmation. _h2 3) les fondations _p De ce qui précède on retiendra qu'une expression '{lambda talk} peut être n'importe quelle combinaison des formes suivantes séparées par des espaces : {pre 1) un mot, cad un groupe de caractères sauf les accolades '{} 2) la forme spéciale {b lambda} : '{lambda {:mots} expression} 3) la forme spéciale {b def} : '{def mot expression} 4) la forme applicative '{expression expression} } _p chacune étant évaluée dans cet ordre, [{b 1 2 3 4}] suivant les règles suivantes : {pre 1) un mot est évalué à lui-même, sauf s'il est placé en première position dans une forme applicative, 2) la forme spéciale {b lambda} crée une fonction ayant {b :mots} pour arguments et expression pour corps, et retourne une référence à cette fonction, enregistrée dans un {b dictionnaire} initialement vide. 3) la forme spéciale {b def} évalue l'expression et retourne comme référence le nom choisi par l'utilisateur. 4) la forme applicative remplace la première par la fonction associée si elle existe et l'applique à la seconde expression, qui peut contenir d'autres expressions, évaluées de manière récursive. } _p l'évaluation se terminant quand il n'y a plus une seule accolade. _p Pour résumer, en deux étapes appelées {b abstraction} et {b application}, '{lambda talk} commence par remplacer les formes spéciales {b lambda} et {b def} par des mots, références à des fonctions ajoutées au dictionnaire, et évalue ensuite les formes imbriquées restantes jusqu’à ce qu’il ne reste plus que des mots. _p Bon, les précisions précédentes peuvent être difficiles à digérer à ce point de l’exposé mais il n'est pas nécessaire d'avoir tout compris pour aller plus loin. Disons qu'elles prendront toute leur valeur au fil de l'exploration qui va suivre. Dans ce qui suit nous allons commencer avec un {b dictionnaire} effectivement vide, nous interdisant dans un premier temps d'utiliser des primitives comme {b [+, -, *, /]} construites sur le langage Javascript. Le dictionnaire sera vraiment {b vide}, et pourtant on va pouvoir construire des structures de données intéressantes comme les booléens, les paires, les listes et une structure de contrôle indispensable, la récursion, permettant de créer des boucles. _p Voyons donc comment. _h3 3.1) les booléens _p Considérons les trois fonctions suivantes : {pre '{def true {lambda {:a :b} :a}} -> {def true {lambda {:a :b} :a}} '{def false {lambda {:a :b} :b}} -> {def false {lambda {:a :b} :b}} '{def si {lambda {:a :b :c} {:a :b :c}}} -> {def si {lambda {:a :b :c} {:a :b :c}}} } _p Notons tout d'abord que ces définitions n'ont rien de bien méchant. On peut se demander à quoi elles peuvent servir. Alors testons : {pre '{true yes no} -> {true yes no} '{false yes no} -> {false yes no} } _p Suivant sa définition la fonction {b true} reçoit deux valeurs, ici {b yes} et {b no} et retourne la première. La fonction {b false} retourne la seconde valeur. Considérons maintenant la fonction {b si} : {pre '{si true yes no} -> {si true yes no} '{si false yes no} -> {si false yes no} } _p A première vue on n'a pas gagné grand chose, à quoi bon utiliser la fonction {b si} et {b true} pour avoir le même résultat obtenu en écrivant simplement {b true yes no} ? On peut dire que la fonction {b si} est un "sucre syntaxique", permettant d'écrire de façon plus lisible le choix entre deux valeurs en fonction d'un test {b si vrai/faux alors ceci ou cela}. _p Notons que {b si} est une fonction évaluant les trois termes, y compris celui qui ne sera pas choisi et ce n'est pas bien malin. Mais patience, cette forme prendra toute sa valeur dans ce qui suit. Auparavant interrogeons-nous sur ce qui se passe si on veut choisir non pas entre deux mots mais entre deux phrases. Ecrire {pre '{si true je dis oui je dis non} -> {si true je dis oui je dis non} '{si false je dis oui je dis non} -> {si false je dis oui je dis non} } _p fonctionne parfaitement mais certainement pas comme on le souhaite. La première expression retourne le premier mot {b je}, en accord avec sa définition, et la seconde retourne ... tout ce qui suit, et pas uniquement le second mot {b dis}, comme on pourrait s'y attendre. Il se trouve que les fonctions de lambdatalk acceptent un nombre de valeurs supérieur au nombre de variables définies et que les valeurs surnuméraires sont simplement capturées par la dernière, le résulta est donc bien {b dis oui je dis non}. Mais ça ne résout en rien notre problème. Voici une façon de le résoudre, un vrai truc de "hacker", on appelle ça un "hack". Rassurez-vous dans la vraie vie on pourra oublier ce mauvais moment : {pre '{si true // la valeur booléene {lambda {} je dis oui} // une fonction sans argument {lambda {} je dis non}} // une fonction sans argument -> {si true {lambda {} je dis oui} {lambda {} je dis non}} } _p Pour l'instant ce n'est pas concluant mais analysons quand même ce résultat. On sait que les expressions {b '{lambda {} je dis oui}} et {b '{lambda {} je dis non}} sont évaluées et remplacées par les références des fonctions créées AVANT l'application de la fonction {b si}. Et la fonction {b si} retourne bien une référence, la référence de la fonction choisie. Il ne reste plus qu'à appliquer cette fonction qui n'attend aucune valeur à ... rien du tout pour obtenir le résultat. Voici donc la bonne façon de faire : {pre '{{si true {lambda {} je dis oui} {lambda {} je dis non}} } -> {{si true {lambda {} je dis oui} {lambda {} je dis non}} } '{{si false {lambda {} je dis oui} {lambda {} je dis non}} } -> {{si false {lambda {} je dis oui} {lambda {} je dis non}} } } _p Ouf ! C'est le moment de relire les règles énoncées plus haut. Tout ceci reste logique et constitue un premier exemple de combinaison utile, une structure de contrôle qui assurera l'ossature de nombreux algorithmes explorés dans ce qui suit. Après avoir construit une seconde structure de donnée nous permettant d'aggréger plusieurs mots à commencer par deux, les {b paires}. _h3 3.2) les paires _p Voici trois nouvelles fonctions : {pre '{def pair {lambda {:a :b :c} {:c :a :b}}} -> {def pair {lambda {:a :b :c} {:c :a :b}}} '{def left {lambda {:c} {:c true}}} -> {def left {lambda {:c} {:c true}}} '{def right {lambda {:c} {:c false}}} -> {def right {lambda {:c} {:c false}}} } _p trois fonctions simples assez similaires aux trois "booléennes". Testons-les {pre '{def P {pair hello world}} -> {def P {pair hello world}} '{left {P}} -> {left {P}} '{right {P}} -> {right {P}} } _p On a compris que la fonction {b pair} aggrège deux mots et que les fonctions {b left} et {b right} retournent respectivement celui de gauche et de droite. On a défini un mécanisme pour regrouper deux mots en une seule entité et accéder à chacun au besoin. Mais il y a quelque chose de nouveau ici. La fonction {b pair} attend trois valeurs {b :a :b :c} et on ne lui en a fourni que deux, {b hello} et {b world}. Il se frouve qu'une fonction lambdatalk accepte sans se plaindre un nombre de valeurs qui peut être différent du nombre de variables définies : _ul si le nombre est le même tout va bien, elle retourne le résultat attendu, _ul nous avons déjà vu que si il y a davantage de valeurs, les valeurs surnuméraires sont accumulées dans la dernière variable et le résultat attendu est retourné, _ul et si il n'y a pas assez de valeurs celles qui sont fournies sont "mémorisées" dans le corps de la fonction et c'est la référence à une nouvelle fonction attendant celles qui manquent qui est retournée. _p Analysons donc les différentes étapes de l'évaluation de l'expression {b '{left {P}}} {pre °° 0: {left {P}} 1: {left {pair hello world}} 2: {left {{lambda {:a :b :c} {:c :a :b}} hello world}}} 3: {left {lambda {:c} {:c hello world}}} 4: {{lambda {:c} {:c true}} {lambda {:c} {:c hello world}} 5: {{lambda {:c} {:c hello world}} true} 6: {true hello world} 7: hello °°} _p Indigeste certes, mais stricte application des règles de remplacement de texte. Construisons deux nouvelles fonctions bien utiles : {pre '{def nil {lambda {:a} true}} -> {def nil {lambda {:a} true}} '{def nil? {lambda {:p} {:p {lambda {:a :b} false}}}} -> {def nil? {lambda {:p} {:p {lambda {:a :b} false}}}} } _p Appliquée à {b nil} la fonction {b nil?} retourne {b true} et appliquée à une paire elle retournera {b false} : {pre '{nil? nil} -> {nil? nil} '{nil? {P}} -> {nil? {P}} } _p Bon ! Un café et on passe à la suite ... les listes. _p Une liste est une paire ... dont le terme de droite est une liste. Exemple: {pre '{def L {pair hello {pair brave {pair new {pair world nil}}}}} -> {def L {pair hello {pair brave {pair new {pair world nil}}}}} } _p où {b nil} définit la fin de liste. On peut utiliser les fonctions {b left} et {b right} pour afficher "manuellement" tous ses termes : {pre '{left {L}} -> {left {L}} '{left {right {L}}} -> {left {right {L}}} '{left {right {right {L}}}} -> {left {right {right {L}}}} '{left {right {right {right {L}}}}} -> {left {right {right {right {L}}}}} } _p Pourrait-on automatiser ce processus dans une boucle ? _h3 3.3) les boucles _p Commençons par tester "le reste" de la liste à chaque étape : {pre '{nil? {right {L}}} -> {nil? {right {L}}} '{nil? {right {L}}} -> {nil? {right {L}}} '{nil? {right {right {L}}}} -> {nil? {right {right {L}}}} '{nil? {right {right {right {L}}}}} -> {nil? {right {right {right {L}}}}} '{nil? {right {right {right {right {L}}}}}} -> {nil? {right {right {right {right {L}}}}}} } _p La fonction {b nil?} retourne donc {b false} pour chaque mot {b hello, brave, new, world} et {b true} au dernier mot, {b nil}. Voici donc, sans explication pour le moment, une fonction affichant "automatiquement" les termes de la liste : {pre '{def display {lambda {:l} {{si {nil? :l} // si fin de list {lambda {:l} } // alors stop {lambda {:l} {left :l} // sinon affiche le premier terme {display {right :l}}} // et affiche la suite } :l} // applique la fonction choisie à :l }} -> {def display {lambda {:l} {{si {nil? :l} {lambda {:l} } {lambda {:l} {left :l} {display {right :l}}}} :l}}} '{display {L}} -> {display {L}} } _p Bingo, on a bien défini une boucle, et sous la forme d'un {b algorithme récursif} en plus ! Pour en comprendre le fonctionnement donnons un nom aux deux lambdas internes : {pre '{def one {lambda {:l} }} '{def two {lambda {:l} {left :l} {disp {right :l}}}} } _p La fonction s'écrit alors : {pre '{def display {lambda {:l} {{si {nil? :l} one two} :l}}} } _p Développons l'expression {b '{display {L}}} : {pre 0: '{display {L}} 1: '{{lambda {:l} {{si {nil? :l} one two} :l}} {L}} // disp est développé 2: '{{si {nil? {L}} one two} {L}} // '{L} a remplacé :l 3: '{{si false one two} {L}} // L n'est pas nil -> false 4: '{two {L}} // false -> two 5: '{{lambda {:l} {left :l} {disp {right :l}}} {L}} // two est développé 6: '{left {L}} '{display {right {L}}} // '{L} a remplacé :l 7: hello '{display {right {L}}} // hello est affiché // et on affiche la suite } _p Et ainsi de suite jusqu'au dernier terme, {b nil}, qui clôt la boucle récursive. Il s'agit de la stricte application des règles de substitution vues plus haut, sans aucune zône d'ombre. La récursion "en douceur" ! _p Que l'on a tout de suite envie de tester sur l'exemple de récursion par excellence, le calcul de la factorielle d'un nombre, {b n!}, qui se définit ainsi : {pre si n = 0 alors n! = 1 sinon n! = n * (n-1)! } _p On va tricher un peu en supposant que le dictionnaire n'est pas si vide que ça et qu'il contient les opérateurs arithmétiques {b *} et {b -} dont nous avons besoin. Voic donc le code récursif : {pre '{def ! {lambda {:n} {{si {= :n 0} {lambda {:n} 1} {lambda {:n} {* :n {! {- :n 1}}}}} :n}}} -> {def ! {lambda {:n} {{si {= :n 0} {lambda {:n} 1} {lambda {:n} {* :n {! {- :n 1}}}}} :n}}} '{! 6} -> {! 6} '{! 100} -> {! 100} } _p On note la resemblance étroite entre la fonction affichant une liste et celle calculant une factorielle, on dispose d'un "pattern" (motif in english) applicable de façon universelle pour générer des boucles. Revenons par exemple à notre liste et ajoutons quelques fonction utiles pour en calculer la longueur, la retourner, et la "concaténer" à elle-même. {pre '{def length {lambda {:l} {{si {nil? :l} {lambda {:l} 0} {lambda {:l} {+ 1 {length {right :l}}}}} :l}}} -> {def length {lambda {:l} {{si {nil? :l} {lambda {:l} 0} {lambda {:l} {+ 1 {length {right :l}}}}} :l}}} '{length {L}} -> {length {L}} '{def reverse {def reverse.r // recursive part {lambda {:a :b} {{si {nil? :a} {lambda {:a :b} :b} {lambda {:a :b} {reverse.r {right :a} {pair {left :a} :b}}}} :a :b}}} {lambda {:a} {reverse.r :a nil}}} // init and recurse -> {def reverse {def reverse.r {lambda {:a :b} {{si {nil? :a} {lambda {:a :b} :b} {lambda {:a :b} {reverse.r {right :a} {pair {left :a} :b}}}} :a :b}}} {lambda {:a} {reverse.r :a nil}}} '{display {reverse {L}}} -> {display {reverse {L}}} '{def concatenate {def concatenate.r {lambda {:a :b} {{si {nil? :b} {lambda {:a :b} :a} {lambda {:a :b} {concatenate.r {pair {left :b} :a} {right :b}}} } :a :b}}} {lambda {:a :b} {concatenate.r {reverse :a} :b}}} -> {def concatenate {def concatenate.r {lambda {:a :b} {{si {nil? :b} {lambda {:a :b} :a} {lambda {:a :b} {concatenate.r {pair {left :b} :a} {right :b}}} } :a :b}}} {lambda {:a :b} {concatenate.r {reverse :a} :b}}} '{display {concatenate {L} {reverse {L}}}} -> {display {concatenate {L} {reverse {L}}}} } _p On pourrait continuer ainsi aussi longtemps que voulu, et même oublier les nombres et les opérateurs arithmétiques empruntés à Javascript et les créer {i ex nihilo}, tout au moins à partir des deux formes spéciales {b lambda} et {b def}. _p Mais l'objectif de ce papier étant d'esquisser la {b fabrique d'un langage}, d'introduire les premiers concepts de base sur {i le plus petit ensemble de mots-clés}, les formes spéciales {b lambda} et {b def}, à savoir : _ul la création de fonctions, appliquées à un nombre variable/quelconque de valeurs, _ul le nommage de constantes et de fonctions, _ul les structures de données, les booléens, les paires, les listes, ... _ul une structure de contrôle incontournable, la récursion. _p et les bases étant supposées acquises, et surtout comprises, nous allons sans plus tarder aborder le {b vrai monde} du code, peuplé de sucres syntaxiques bien agréables et d'ensemble structurés de primitives assemblés en bibliothèques spécialisées dans différents domaines, les maths, le web, la 2D/3D, ... _h2 4) les sucres syntaxiques, if & let _p Jusqu'ici nous n'avons utilisé que deux formes spéciales, {b lambda} et {b def}, mais '{lambda talk} en contient {b neuf} au total, dont les formes {b if} et {b let}, des sucres syntaxiques qui vont nous permettre d'alléger le code, le rendre plus lisible et plus performant. _h3 4.1) '{if bool then one else two} _p Vous vous souvenez du "hack" utilisé dans la fonction {b si} de la section 3.1) sur les booléens. La forme spéciale {b if} se charge de toutes les subtilités sous le capot et permet cette écriture allégée : {pre '{if true then I say yes else I say no} -> {if true then I say yes else I say no} } _p De même la factorielle {pre '{def fac {lambda {:n} {{when {= :n 0} {lambda {:n} 1} {lambda {:n} {* :n {fac {- :n 1}}}}} :n}}} } _p s'écrira de façon bien plus lisible : {pre '{def fac {lambda {:n} {if {= :n 0} then 1 else {* :n {fac {- :n 1}}}}}} -> {def fac {lambda {:n} {if {= :n 0} then 1 else {* :n {fac {- :n 1}}}}}} '{fac 6} -> {fac 6} '{fac 100} -> {fac 100} } _h3 4.2) '{let { {:var val} ... } expression} {pre '{{lambda {:x :y} {+ :x :y} } 3 4} -> {{lambda {:x :y} {+ :x :y}} 3 4} } _p s'écrit maintenant {pre '{let { {:x 3} {:y 4} } {+ :x :y} } -> {let { {:x 3} {:y 4} } {+ :x :y} } } {pre '{def area {lambda {:a :b :c} {{lambda {:a :b :c :s} {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} } :a :b :c {/ {+ :a :b :c} 2} }}} } _p devient {pre '{def area {lambda {:a :b :c} {let { {:a :a} {:b :b} {:c :c} {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }}} -> {def area {lambda {:a :b :c} {let { {:a :a} {:b :b} {:c :c} {:s {/ {+ :a :b :c} 2}} } {sqrt {* :s {- :s :a} {- :s :b} {- :s :c}}} }}} '{area 1 1 {sqrt 2}} -> {area 1 1 {sqrt 2}} } _h2 5) les primitives _p Le dictionnaire de '{lambda talk} contient un ensemble de primitives prédéfinies : {prewrap {b HTML :} @, div, span, a, ul, ol, li, dl, dt, dd, table, tr, td, h1, h2, h3, h4, h5, h6, p, b, i, u, center, br, hr, blockquote, del, sup, sub, code, img, pre, textarea, audio, video, source, select, option, object, canvas, input, iframe, hide, prewrap, show_last_code, {b SVG :} svg, line, rect, circle, ellipse, polygon, polyline, path, text, g, mpath, use, textPath, pattern, image, clipPath, defs, animate, set, animateMotion, animateTransform, title, desc, turtle, {b MATH :} +, *, -, /, %, <, >, <=, >=, =, not, or, and, abs, acos, asin, atan, ceil, cos, exp, floor, pow, log, random, round, sin, sqrt, tan, min, max, PI, E, date, long_add, long_mult, {b WORDS :} W.equal?, W.empty?, W.length, W.get, W.first, W.rest, W.last, W.slice, W.reverse, W.sort, W.lib, {b SENTENCES :} S.equal?, S.empty?, S.length, S.first, S.rest, S.last, S.get, S.slice, S.serie, S.map, S.reduce, S.replace, S.reverse, S.sort, S.lib, {b ARRAYS :} A.new, A.disp, A.join, A.split, A.array?, A.null?, A.empty?, A.in?, A.equal?, A.length, A.get, A.first, A.last, A.rest, A.slice, A.duplicate, A.reverse, A.concat, radic, A.map, A.set!, A.addlast!, A.sublast!, A.addfirst!, A.subfirst!, A.reverse!, A.sort!, A.lib, {b PAIRS :} P.new, cons, P.pair?, P.left, car, P.right, cdr, P.disp, P.lib, {b LOCAL_STORAGE :} LS.display, LS.setItem, LS.getItem, LS.removeItem, LS.clear, } _p Cet ensemble est extensible de deux façons différentes, en utilisant la syntaxe '{lambda talk} ou la syntaxe javascript. _ul 1) syntaxe '{lambda talk} _ul20 1.1) la forme spéciale {b '{lambda {:args} body}} ajoute au dictionnaire une fonction ayant {b :args} comme arguments et {b body} comme corps, _ul20 1.2) la forme spéciale {b '{def nom expression}} ajoute au dictionnaire une expression évaluée et nommée. _ul 2) syntaxe javascript _ul20 la forme spéciale {b script} permet d'ajouter au dictionnaire une fonction suivant la syntaxe javascript, par exemple l'équivalent de la fonction {b smart_add} définie en section 2) alias : {pre LAMBDATALK.DICT["js_smart_add"] = function() '{ var args = LAMBDATALK.supertrim(arguments[0]).split(" "), a = args[0], b = args[1]; return "la somme de " + a + " et " + b + " est égale à " + (a+b); }; // '{js_smart_add 3 4} -> la somme de 3 et 4 est égale à 7 } _p à suivre ... _h2 6) les bibliothèques _p Il est intéresssant de regrouper par familles les primitives prédéfinies et les fonctions définies par l'utilisateur (via les formes spéciales {b lambda} et {b def}), formant ainsi des "bibliothèques" {b lib_xxx, lib_yyy, ...}. Ces bibliothèques peuvent être appelées dans n'importe qu'elle page du wiki via la forme spéciale {b '{ require lib_xxx lib_yyy ...}}. _p _p Le monde du web est rempli de code javascript dont '{lambda talk} peut tirer parti. Par exemple [[Jonas Raoni Soares Silva|http://jsfromhell.com/]] a écrit une bibliothèque de fonctions, {b BigNumber}, permettant de travailler sur des nombres de taille quelconque. Par le biais de fonctions '{lambda talk} assurant l'interface approprié il devient possible de les ajouter au dictionnaire de '{lambdatalk} et de les utiliser directement dans une page wiki : {require lib_BN} {prewrap '{def BN.fac {lambda {:n} {if {< :n 1} then 1 else {BN.* :n {BN.fac {- :n 1}}}}}} -> {def BN.fac {lambda {:n} {if {< :n 1} then 1 else {BN.* :n {BN.fac {- :n 1}}}}}} '{BN.fac 6} -> {BN.fac 6} '{BN.fac 100} -> {BN.fac 100} } _p Le wiki contient un certain nombre de pages contenant actuellement les bibliothèques suivantes {b lib_math, lib_BN, lib_complex, lib_matrix, lib_list, lib_hash, lib_beta, lib_agora, lib_uncover, lib_watch, lib_sifr, ...}. _h2 conclusion _p Et bien voilà, ce n'était pas si compliqué ! Non ? Ah bon, recommençons donc. _p {i Alain Marty 2020/12/19-21} _img http://epsilonwiki.free.fr/epsilonwiki/skins/peak.jpg {style pre { color:#008; box-shadow:0 0 8px #000; padding:5px; } }
lambdaway v.20211111