lambdaway
::
concepts
7
|
list
|
login
|
load
|
|
{toggle} {toggle2} _h1fr la fabrique du code _h1en the code factory {{block} {uncover http://colette.cerda.free.fr/coco.c/data/t2_orchestre3.jpg 100 500 ORCHESTRE.3{div}encre monotype sur papier 18x24cm{div}colette} _h2 introduction °°° {center {@ style="width:400px; margin:auto;"} _pen {i {sup " You can click on the top-left button to switch between french and english and on the top-right button to switch between a vertical and a horizontal display. "}} _pfr {i {sup " Vous pouvez cliquer sur le bouton en haut à gauche pour passer du français à l'anglais et sur le bouton en haut à droite pour passer d'un affichage vertical à un affichage horizontal. "}} } °°° {blockquote _pfr {i « En sciences et techniques, notamment en informatique et en théorie de l'information, {b un code est un système de règles de transcription} qui, à tout symbole d'un jeu de caractères (alphabet source) assigne de manière univoque un caractère ou une chaîne de caractères pris dans un jeu de caractères éventuellement différent (alphabet cible). » (Wikipedia)} _pen {i « In science and technology, especially in computer science and information theory, {b a code is a system of transcription rules} which, to any symbol of a set of characters (source alphabet) univocally assigns a character or a string of characters taken from a possibly different set of characters (target alphabet). » (Wikipedia)} } _pfr Pour pouvoir {b coder}, utiliser correctement un langage de programmation, il faut ... connaître un minimum d'anglais ... et digérer tout un ensemble de définitions et de concepts dont voici une liste non exhaustive : _pen To be able to {b code}, to use a programming language correctly, you need to ... have a basic knowledge of English ... and digest a whole set of definitions and concepts: {center {prewrap expression, abstraction, application, constants, bound variables, free variables, anonymous functions, named functions, arguments, body, arity, partial application, global context, local context, lexical context, blocks, side effects, pointer, pointed value, characters, words, strings, logical structures: boolean, branching, predicate, loop structures: iteration, recursion, terminal or not, data structures: tuples, pairs, lists, trees, arrays, mutable, immutable objects, states, assignment, referential transparency, operator priority, combinatorial, lazy, gluttonous, value-based, name-based, sequential, parallel evaluation, syntactic sugar, functional, imperative, declarative, object-based, future, delay, primitive, dictionary, library, homoiconicity, ... }} _pfr sans oublier les mots-clé des langages qui ne peuvent pas être utilisés comme identificateurs de variables, comme ici en Javascript _pen without forgetting the keywords of languages that cannot be used as variable identifiers, as here in Javascript {center {prewrap await break case catch class const continue debugger default delete do else enum export extends false finally for function if implements import in instanceof interface let new null package private protected public return super switch static this throw try True typeof var void while with yield }} _pfr Chacun a sa propre approche, ses introductions, ses manuels d'utilisation et ses compilations d'exemples à profusion, généralement dépendants du langage utilisé quand il ne s'agit pas d'approches théoriques délicates dont le lambda-calcul est l'exemple type. Dans lesquels il est difficile de trouver les fondements, l'unité. Je m'en suis contenté pendant toutes ces années où je codais (en C++, macros POVRAY, Ruby, Javascript, ...) pour explorer les algorithmes de l'infographie (modélisation 3D, Ray tracing, rendu, ...). En vieillissant, cela ne me suffit plus, je veux comprendre la magie qui se cache derrière tous ces outils, je veux ouvrir le capot. _pen Each one has its own approach, introductions, user manuals and compilations of examples in profusion, generally dependent on the language used when they are not tricky theoretical approaches of which lambda-calculus is the typical example. In which it is difficult to find the foundations, the unity. I was satisfied with it during all these years when I was coding (in C++, POVRAY's macros, Ruby, Javascript, ...) to explore the algorithms of computer graphics (3D modeling, Ray tracing, rendering, ...). In my old age, this is not enough for me anymore, I want to understand the magic behind all these tools, I want to open the hood. _pfr J'ai donc concocté une autre approche, en partant d'une base aussi réduite que possible et en définissant un petit ensemble de briques avec lesquelles construire les structures de données et de contrôle communes à tous les langages, qui leur serviront toujours de guide dans leur apprentissage. Vous oublierez lambdatalk, le langage qui m'accompagne dans ce voyage, mais vous garderez à l'esprit certains des concepts essentiels qui sous-tendent l'acte de coder. Du moins je l'espère. _pen So I concocted another approach, starting from a foundation as small as possible and defining a small set of bricks with which to build the data and control structures common to all languages, which will always serve as a guide in their learning. You will forget lambdatalk, the language that accompanies me in this journey, but you will keep in mind some of the essential concepts that underlie the act of coding. At least I hope so. _p Plan : {pre introduction IIFE, lambda & def lambda{sup calc}: booleans, pairs, trees, lists, hanoï lambda{sup talk}: let & if, primitives, sierpinsky conclusion } {draw_cyclic 2 4} ;; _img http://messirehorus.fr/pics/horus/oeil.png {{geek} _h4en This page is an editable lambdatalk program! _h4fr Cette page est un programme lambdatalk modifiable ! _pfr Ce qui veut dire que vous pouvez ouvrir l'éditeur du code de la page - en cliquant sur le mot "concepts" du titre en haut et à gauche de la page - survoler le code en repérant les correspondances avec l'affichage - c'est facile pour les blocs de texte pur - et, une fois familiarisés, vous pouvez modifier à votre guise, sans autre risque que de devoir recharger la page si les choses vont mal. C'est en bidouillant le code qu'on finit par le comprendre. _pen This means that you can open the page's code editor - by clicking on the word "concepts" in the title at the top left of the page - hover over the code, spotting matches with the display - this is easy for pure text blocks - and, once you're familiar with it, you can modify it as you like, without any risk other than having to reload the page if things go wrong. It's only by tinkering with the code that you get the hang of it. } } {{block} {uncover http://colette.cerda.free.fr/coco.c/data/e_aok2.jpg 100 500 ORCHESTRE.3{div}encre monotype sur papier 18x24cm{div}colette} _h2fr lambda _h2en lambda _pfr Mon approche est donc construite sur {b lambdatalk}, le langage qui anime les pages de ce wiki, lointain dialecte du lambda-calcul matiné d'un peu de LISP. Il faut bien une base et c'est probablement la plus simple et la plus stable, même si elle apparaît a priori la plus improbable. _pen My approach is therefore built on {b lambdatalk}, the language that animates the pages of this wiki, a distant dialect of lambda-calculus with a bit of LISP. There has to be a basis and this is probably the simplest and most stable one, even if it seems a priori the most unlikely. _h3fr IIFE _h3en IIFE _pfr Tout commence avec un simple processus de remplacement de texte _pen It all starts with a single text rewriting process {pre {b replace} some words1 {b in} some expression {b by} some other words2 -> words3 } _pfr immédiatement ré-écrit sous la forme d'une expression parenthésée, appelée {b IIFE} pour des raisons données plus loin : _pen immediately rewritten as a parenthetical expression, so-called {b IIFE} for reasons given later: {pre '{{lambda {words1} // variables expression // body containing words1 } words2} // values -> words3 // output } _pfr dans laquelle _pen in which _lfr 1) {code words1, words2, words3} sont des séquences de mots ; un {b mot} - word in english - est tout groupe de caractères excepté les espaces et les accolades {code '{}}, _len 1) {code words1, words2, words3} are sequences of words ; a {b word} is any group of characters except spaces and braces {code '{}}, _lfr 2) {code '{lambda {words1} expression}} représente une {b fonction anonyme} ayant words1 comme arguments, des mots que l'on retrouve en tout ou partie comme variables dans {b expression} définissant le corps de la fonction, et destinées à être remplacées par {code words2} pour produire {code words3}, _len 2) {code '{lambda {words1} expression}} represents an {b anonymous function} having {code words1} as arguments - words that are found in whole or in part as {b variables} in {b expression} defining the body of the function - and intended to be replaced by {code words2} to produce {code words3}, _lfr 3) {b expression} est une séquence de mots et/ou d'expressions, il s'agit donc d'une définition récursive qui permet la construction d'une cascade d'expressions imbriquées sans limite théorique. _len 3) {b expression} is a sequence of words and/or expressions, it's therefore a {b recursive definition} which allows the construction of a cascade of nested expressions without theoretical limit. _pfr L{b 'IIFE} est évaluée en commençant par la lambda expression, remplacée par une {b référence}, un mot, enregistrée dans un {b dictionnaire} initialement vide. _pen The {b IIFE} is evaluated starting with the lambda expression, replaced by a {b reference}, a word, stored in a {b dictionary} initially empty. _pfr L{b 'IIFE} représente {b l'application} à une séquence de mots, {code words2}, d'une {b fonction anonyme} définie à la volée et produisant immédiatement une séquence de mots, {b words3}. On donne parfois à cette "{i expression contenant une fonction immédiatement invoquée}" le nom de {b IIFE}, de l'anglais "Immediately Invoqued Function Expression", nom que je garderai pour la suite. _pen The {b IIFE} represents the {b application} to a given sequence of words, {code words2}, of an {b anonymous function} defined on the fly and immediately producing a sequence of words, {code words3}. This is why this "{i {b I}mmediately {b I}nvoked {b F}unction {b E}xpression}" is called {b IIFE}, a name I will keep for the following. _pfr {b Et c'est tout !} Un ensemble infini de {b mots} et de {b fonctions} pouvant être combinés à l'infini, flottant sur un dictionnaire vide pour produire des {b mots} ... envoyés au navigateur web qui en fait ce qu'il peut. _pen {b And that's it!} Floating on an empty dictionary, an infinite set of {b words} and {b functions} which can be combined ad infinitum to produce {b words} ... sent to the web browser which does what it can with them. _pfr Passons à la pratique. Suivant ces règles l'expression _pen Let's move on to practice. According to these rules the expression {pre '{{lambda {:a :b} My name is :b, :a :b. } James Bond} } _pfr où les variables {b a & b} sont préfixées par le caractère "{b :}" pour les marquer comme variables, est immédiatement remplacée par _pen where variables {b a & b} are prefixed by the character "{b :}" to mark them as variables, is immediately replaced by {pre My name is Bond, James Bond. } _pfr où l'on voit que les deux mots {b James & Bond} ont remplacé toutes les occurences des arguments {b :a & :b} dans le corps de la fonction "{b My name is :b, :a :b.}" Voyez-vous la raison de préfixer d'un "{b :}" les variables {b a & b} ? _pen where we see that the two words {b James & Bond} have replaced all occurrences of the arguments {b :a & :b} in the body of the function "{b My name is :b, :a :b.}" Do you see the reason for prefixing the variables {b a & b} with "{b :}"? _pfr Nous constatons que tout ceci est une simple affaire de remplacement de texte, rien d'autre. Il est important de savoir qu'en théorie nous n'avons besoin de rien d'autre pour construire un langage de programmation complet. On pourrait composer à l'infini des IIFE pour construire des booléens, des branchements, des nombres, des listes, etc, mais ... _pen We see that all this is just a matter of replacing text, nothing else. It is important to know that in theory we do not need anything else to build a complete programming language. We could compose infinite IIFEs to build booleans, branches, numbers, lists, etc... but ... _h3fr def _h3en def _pfr Le coeur d'une IIFE est constitué par l'expression {b '{lambda {words} expression}}. Mais pour en faciliter les manipulations nous devons introduire une seconde expression parenthésée, optionnelle mais bien utile _pen The core of an IIFE is the expression {b '{lambda {words} expression}}. But to make it easier to handle, we have to introduce a second parenthesized expression, optional but very useful {pre '{def nom expression} } _pfr permettant de nommer une expression. Par exemple nous appelerons {b HI} l'expression parenthésée interne de notre IIFE _pen to name an expression. For example, we will call {b HI} the internal parenthetical expression of our IIFE {pre '{def HI {lambda {:a :b} My name is :b, :a :b.}} -> {def HI {lambda {:a :b} My name is :b, :a :b.}} } _pfr et l'expression complète pourra ainsi être écrite tout simplement _pen and the complete expression can be written simply {pre '{HI James Bond} -> {HI James Bond} } _pfr Chemin faisant nous avons ajouté une fonction, {b HI}, au dictionnaire du langage, qui était vide jusqu'alors, et nous pouvons l'utiliser autant de fois que nous le voulons _pen Along the way we have added a function, {b HI}, to the language dictionary, which was empty until then, and we can use it as often as we like {prewrap '{HI Monica Bellucci} -> {HI Monica Bellucci} '{HI Marie Curie} -> {HI Marie Curie} '{HI Nicolas de Caritat de Condorcet} -> {HI Nicolas de Caritat de Condorcet} } _h3fr détails techniques _h3en technical details _pfr Le dernier exemple appelle quelques remarques. La fonction {b HI} est construite pour recevoir deux valeurs, que se passe-t'il si tel n'est pas le cas ? Etudions tous les cas possibles. _pen The last example calls for some remarks. The function {b HI} is built to receive two values, what happens if this is not the case? Let's study all the possible cases. _h4fr 1) aucune valeur _h4en 1) zero value {pre '{{lambda {:a :b} My name is :b, :a :b.}} -> {{lambda {:a :b} My name is :b, :a :b.}} } _pfr Il s'agit d'un mot d'apparence étrange qui n'est autre qu'une nouvelle {b référence} de la {b même fonction} ajoutée dans le dictionnaire du langage. Les références sont choisies par lambdatalk à des fins internes et ne sont pas connues par l'utilisateur. C'est la raison pour laquelle celui-ci va s'empresser de les remplacer par un nom via la forme spéciale {b def}. _pen This is a strange looking word which is nothing else than a new {b reference} of the {b same function} added in the language dictionary. References are chosen by lambdatalk for internal purposes and are not known by the user. This is the reason why the user will hasten to replace them by a name via the special form {b def}. _h4fr 2) une valeur _h4en 2) one value {pre '{{lambda {:a :b} My name is :b, :a :b.} James} -> {{lambda {:a :b} My name is :b, :a :b.} James} } _pfr Cette expression est remplacée à la volée par une nouvelle fonction n'ayant qu'un seul argument, {b :b} _pen This expression is replaced on the fly by a new function with only one argument, {b :b} {pre '{lambda {:b} My name is :b, James :b} } _pfr dans laquelle la variable {b :a} a été remplacée par {b James}. Et cette nouvelle IIFE _pen in which the variable {b :a} has been replaced by {b James}. And this new IIFE {pre '{{lambda {:b} My name is :b, James :b.} Bond} } _pfr aboutira finalement au résultat attendu. Cette possibilité d{b 'application partielle} est vitale dans le cas d'un langage comme lambdatalk où les fonctions sont totalement pures, sans variables libres tirant leurs valeurs d'un environnement lexical et sans effets de bord. Dans lambdatalk les fonctions ne sont que des machines à remplacer du texte, sans autre contact avec l'environnement que le dictionnaire global où sont conservées les constantes, par exemple {b π}, et les noms des fonctions primitives, par exemple {b sin}us. _pen will eventually lead to the awaited result. This possibility of {b partial application} is required in the case of a language like lambdatalk where functions are totally pure, without free variables taking their values from a lexical environment and without side effects. In lambdatalk functions are just text replacement machines, with no other contact with the environment than the global dictionary where constants, e.g. {b π}, and primitive function names, e.g. {b sin}us, are kept. _h3fr 3) deux valeurs _h4en 3) two values {pre '{{lambda {:a :b} My name is :b, :a :b.} James Bond} -> {{lambda {:a :b} My name is :b, :a :b.} James Bond} } _pfr La fonction reçoit les deux valeurs attendues et retourne le résultat espéré. _pen The function receives the two expected values and returns the expected result. _h4fr 4) trois valeurs et plus _h4en 4) three or more values {prewrap '{{lambda {:a :b} My name is :b, :a :b.} Nicolas de Caritat de Condorcet} -> {{lambda {:a :b} My name is :b, :a :b.} Nicolas de Caritat de Condorcet} } _pfr Dans cet exemple observons que le mot Nicolas a été "capturé" par la variable :a et que les quatre mots suivants "de Caritat de Condorcet" ont été "capturés" par la variable :b. Ce type de fonction est dit {b variadique}. _pen In this example let's observe that the word Nicolas has been "captured" by the variable :a and that the four following words "de Caritat de Condorcet" have been "captured" by the variable :b. Such a function is called {b variadic}. _pfr L{b 'application partielle} et la {b variadicité} sont deux intéressantes propriétés des fonctions de lambdatalk. Elles sont de plus utilisables de façon totalement transparente, ce qui n'est pas le cas de tous les langages. _pen {b Partial application} and {b variadicity} are two interesting properties of lambdatalk functions. And moreover they can be used in a totally transparent way, which is not the case for all languages. _pfr Nous sommes à présent équipés de deux formes spéciales, {b lambda & def}, avec lesquelles nous pouvons créer des fonctions et leur donner un nom. _pen We are now equipped with two special forms, {b lambda & def}, with which we can create functions and give them a name. _h3fr constantes _h3en constants _pfr En général une fonction attend un ou plusieurs mots et retourne d'autres mots. Il existe des fonctions qui n'attendent rien, par exemple _pen In general a function expects one or more words and returns other words. There are functions that don't expect anything, for example {pre '{def HBNW {lambda {} Hello brave new World}} -> {def HBNW {lambda {} Hello brave new World}} '{HBNW} -> {HBNW} } _pfr Pour retrouver le contenu associé au nom {b HBNW} nous devrons écrire {b '{HBNW}}, c'est à dire appliquer la fonction à ... rien. Rien d'étonnant. Nous appelerons {b constante} une fonction qui retourne toujours la même valeur et nous pourrons même en simplifier la définition _pen To find the content associated with the name {b HBNW} we will have to write {b '{HBNW}}, i.e. apply the function to ... nothing. Nothing surprising. We will call {b constant} a function that always returns the same value and we can even simplify its definition {pre '{def HBNW Hello brave new World} -> HBNW '{HBNW} -> {HBNW} } _pfr sans oublier d'encadrer son nom entre deux accolades chaque fois que nous en voudrons la valeur. _pen without forgetting to enclose its name between two braces each time we want its value. _pfr Le voyage peut maintenant commencer dans le monde du code. Mais ... _pen The journey can now begin into the world of code. But ... {{geek} _pfr Mais si avant de démarrer vous souhaitez contrôler le moteur qui fait tout le travail, ouvrez le [[capot|?view=kernel]], voici le code javascript chargé de l'évaluation du code lambdatalk : _pen But if before starting you want to check the engine who does the job, open the [[hood|?view=kernel]], here is the javascript code in charge of the evaluation of the lambdatalk code: {prewrap °° var KERNEL=function(){var r=/\(([^\s()]*)(?:[\s]*)([^()]*)\)/g,a={},t=0,g=function(n){for(;n!==(n=n.replace(r,e)););return n},e=function(){var n=arguments[1]||"",r=arguments[2]||"";return a.hasOwnProperty(n)?a[n].apply(null,[r]):"«‚"+n+" "+r+"»"},f=function(n,r,e,t){for(;n!==(n=u(n,r,e,t)););return n},s=function(n){var r=n.indexOf(")"),e=n.substring(1,r),i=""===e?[]:e.split(" "),l=n.substring(r+2),r="_LAMB_"+t++,l=f(l,"lambda",s);return a[r]=function(){var n=arguments[0],r=""===n?[]:n.split(" "),e=l;if(r.length< i.length){for(var t=0;t< r.length;t++)e=e.replace(RegExp(i[t],"g"),r[t]);n=i.slice(r.length).join(" "),e=s("("+n+") "+e)}else if(r.length===i.length)for(t=0;t< i.length;t++)e=e.replace(RegExp(i[t],"g"),r[t]);else{var u=r.slice(0,i.length);u[i.length-1]=r.slice(i.length-1,r.length).join(" ");for(t=0;t< i.length;t++)e=e.replace(RegExp(i[t],"g"),u[t])}return g(e)},r},i=function(n,r){var e=(n=f(n,"def",i,!1)).search(/\s/),t=n.substring(0,e).trim(),u=n.substring(e).trim();return"_LAMB_"===u.substring(0,6)?a[t]=a[u]:(u=g(u),a[t]=function(){return u}),r?t:""},u=function(n,r,e,t){var u=l(r="("+r+" ",n);return"none"===u?n:n.replace(r+u+")",e(u,t))},l=function(n,r){var e=r.indexOf(n);if(-1==e)return"none";for(var n=n.length,t=1,u=e;0< t;)u++,"("==r.charAt(u)?t++:")"==r.charAt(u)&&t--;return r.substring(e+n,u)};return{evaluate:function(n){return n=f(n,"lambda",s),n=f(n,"def",i,!0),n=g(n)}}}();LAMBDATALK.DICT.eval=function(){var n=arguments[0].trim();return KERNEL.evaluate(n)}; °°} _pfr Pas plus, pas moins. _pen No more, no less. } } {{block} {uncover http://colette.cerda.free.fr/coco.c/data/e_d1.jpg 100 500 ORCHESTRE.3{div}encre monotype sur papier 18x24cm{div}colette} _h2fr lambda{sup calc} _h2en lambda{sup calc} _pfr La fonction {b HI} est facile à lire et à écrire, elle est facile à comprendre mais pas vraiment utile. Voici un jeu de neuf fonctions à peine plus complexes et beaucoup plus utiles qui introduisent les {b branchements} et les {b agrégats de données}, qui nous serviront de briques pour construire des structures récursives. _pen The {b HI} function is easy to read and write, easy to understand but not really useful. Here is a set of nine slightly more complex and much more useful functions that introduce {b branches} and {b data aggregates}, which will serve as building blocks for us to construct recursive structures. {center {b [ TRUE, FALSE, IF, PAIR, LEFT, RIGHT, NIL, !NIL, NIL? ]}} {center ...} _h3fr booléens _h3en booleans {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 IF {lambda {:a :b :c} {:a :b :c}}} -> {def IF {lambda {:a :b :c} {:a :b :c}}} '{TRUE James Bond} -> {TRUE James Bond} '{FALSE James Bond} -> {FALSE James Bond} '{IF TRUE James Bond} -> {IF TRUE James Bond} '{IF FALSE James Bond} -> {IF FALSE James Bond} } _pfr Tout langage de programmation définit les valeurs {b vrai & faux}, appelées {b true & false} dans lambdatalk. Ici nous supposons qu'elles n'existent pas et nous les définissons comme deux fonctions, {b TRUE & FALSE}, recevant deux valeurs et retournant la première ou la seconde. Nous ajoutons une fonction "optionnelle", {b IF}, qui n'apporte pas grand chose si ce n'est une expression plus lisible du choix entre deux valeurs commandé par une fonction {b predicat} retournant, {b TRUE } ou {b FALSE}. _pen Any programming language defines the values {b true & false}, called {b true & false} in lambdatalk. Here we assume they don't exist and define them as two functions, {b TRUE & FALSE}, receiving two values and returning the first or the second. We add an "optional" function, {b IF}, which doesn't bring much except a more readable expression of the choice between two values controlled by a function {b predicate} returning, {b TRUE } or {b FALSE}. {{geek} _pen {b Note} OK, if the {b TRUE} & {b FALSE} functions are easy to understand when one understand the {b HI} function , the {b IF} function contains a strange {b '{:a :b :c}} expression which is not easy to understand. So replace {b IF} and {b TRUE} by their lambda definitions in {b '{IF TRUE James Bond}}, go on, "do some algebra", and be convinced that the sequence of replacements will lead to {b James}. Let's do it: _pfr {b Note} OK, si les fonctions TRUE & FALSE sont faciles à comprendre quand on comprend la fonction HI, la fonction IF contient une étrange expression {b '{:a :b :c}} qui n'est pas facile à comprendre. Remplacez donc IF et TRUE par leurs définitions lambda dans {b '{IF TRUE James Bond}}, continuez, "faites de l'algèbre", et soyez convaincu que la séquence de remplacements mènera à James. Faisons-le : {pre '{IF TRUE James Bond} -> '{{lambda {:a :b :c} {:a :b :c}} TRUE James Bond} -> '{TRUE James Bond} -> '{{lambda {:a :b} :a} James Bond} -> James } _p Got it? _pfr En fait {b '{IF TRUE James Bond}} n'est qu'une façon agréable d'écrire cette complexe IIFE _pen In fact {b '{IF TRUE James Bond}} is just a nice way to write this complex IIFE {pre '{{lambda {:a :b :c} {:a :b :c}} {lambda {:a :b} :a} James Bond} } _pen Once more it's essential to understand that it's nothing but text replacement. Never forget that a name is nothing but an alias to the bounded expression. For instance {b TRUE} is equivalent to {b '{lambda {:a :b} :a}}, both are interchangeable. _pfr Une fois de plus, il est essentiel de comprendre qu'il ne s'agit que d'un remplacement de texte. N'oubliez jamais qu'un nom n'est rien d'autre qu'un alias d'une expression fournie. Par exemple, {b TRUE} est équivalent à {b '{lambda {:a :b} :a}}, les deux sont interchangeables. } _pfr Maintenant attachez vos ceintures... _pen Now fasten your seat belt... _h3fr paires _h3en pairs {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}}} } _pfr Une {b paire} est un agrégat de deux mots construit en utilisant la fonction {b PAIR}. Les fonctions {b LEFT & RIGHT} retournent les mots de gauche et de droite. _pen A {b pair} is an aggregate of two words constructed using the {b PAIR} function. The functions {b LEFT & RIGHT} return the left and right words. {pre '{def JB {PAIR James Bond}} -> {def JB {PAIR James Bond}} '{LEFT {JB}} -> {LEFT {JB}} '{RIGHT {JB}} -> {RIGHT {JB}} } _pfr A priori il semble que les fonctions {b TRUE & FALSE} et {b LEFT & RIGHT} sont identiques mais en fait la différence est importante. Les deux premières agissent sur deux mots sans lien entre eux, alors que les secondes agissent sur un seul mot, la paire, un objet contenant deux mots, une structure de données élémentaire avec laquelle on va pouvoir construire des structures de données plus grandes, notamment des listes et des arbres. _pen At first sight it seems that the functions {b TRUE & FALSE} and {b LEFT & RIGHT} are identical but in fact the difference is important. The first two functions act on two unrelated words, while the second ones act on a single word, the pair, an object containing two words, an elementary data structure with which we can build larger data structures, such as lists and trees. {{geek} _pfr {b Note} L'évaluation de l'expression {b '{LEFT {JB}}} mérite d'être détaillée. En voici les étapes : _pen {b Note} The evaluation of the expression {b '{LEFT {JB}}} is worthy of some detail. Here are the steps: {pre 0: '{LEFT {JB}} } _pfr JB est remplacé par sa définition _pen JB is replaced by its definition {pre 1: '{LEFT {PAIR James Bond}} } _pfr PAIR est remplacé par sa définition _pen PAIR is replaced by its definition {pre 2: '{LEFT {{lambda {:a :b :c} {:c :a :b}} James Bond}} } _pfr '{{lambda {:a :b :c} {:c :a :b}} James Bond} est une application partielle créant une nouvelle lambda, '{lambda {:c} {:c James Bond}}, dont est retournée la référence, disons _LAMB_1234, _pen '{{lambda {:a :b :c} {:c :a :b}} James Bond} is a partial application creating a new lambda, '{lambda {:c} {:c James Bond}}, of which is returned the reference, say _LAMB_1234, {pre 3: '{LEFT _LAMB_1234} } _pfr LEFT est remplacé par sa définition _pen LEFT is replaced by its definition {pre 4: '{{lambda {:c} {:c TRUE}} _LAMB_1234} } _pfr :c est remplacé par _LAMB_1234 _pen :c is replaced by _LAMB_1234 {pre 5: '{_LAMB_1234 TRUE} } _pfr _LAMB_1234 est remplacé par sa lambda expression _pen _LAMB_1234 is replaced by its lambda expression {pre :6 '{{lambda {:c} {:c James Bond}} TRUE} } _pfr :c est remplacé par TRUE _pen :c is replaced by TRUE {pre 7: '{TRUE James Bond} } _pfr TRUE est remplacé par sa définition _pen TRUE is replaced by its definition {pre 8: '{{lambda {:a :b} :a} James Bond} } _pfr :a est remplacé par James _pen :a is replaced by James {pre 9: James } } _pfr Et voilà ! _pen Et voilà ! _pfr Une paire est le résultat d'une application partielle, c'est donc une fonction dont la référence ressemble à {b _LAMB_4567}. On est donc amené à définir une fonction, {b P.DISP}, l'affichant par exemple sous la forme de ses deux éléments entre parenthèses et séparés par une virgule. _pen A pair is the result of a partial application, so it is a function whose reference looks like {b _LAMB_4567}. We therefore have to define a function, {b P.DISP}, displaying it for example as its two elements between brackets and separated by a comma. {pre '{def P.DISP {lambda {:p} ({LEFT :p},{RIGHT :p}) }} -> {def P.DISP {lambda {:p} ({LEFT :p},{RIGHT :p}) }} '{P.DISP {JB}} -> {P.DISP {JB}} } _pfr Notons qu'on peut de façon analogue définir une fonction créant une nouvelle paire dans laquelle les deux éléments sont inversés _pen Note that we can similarly define a function that creates a new pair in which the two elements are inverted {pre '{def P.SWAP {lambda {:p} {PAIR {RIGHT :p} {LEFT :p}} }} -> {def P.SWAP {lambda {:p} {PAIR {RIGHT :p} {LEFT :p}} }} '{P.DISP {P.SWAP {JB}}} -> {P.DISP {P.SWAP {JB}}} } _pfr On définit enfin trois fonctions permettant de tester si un mot est une paire vide, {b NIL}, ou pas _pen Finally, we define three functions to test if a word is an empty pair, {b NIL}, or not {pre '{def NIL {lambda {} TRUE}} -> {def NIL {lambda {} TRUE}} '{def !NIL {lambda {} FALSE}} -> {def !NIL {lambda {} FALSE}} '{def NIL? {lambda {:c} {:c !NIL}}} -> {def NIL? {lambda {:c} {:c !NIL}}} '{NIL? NIL} -> {NIL? NIL} '{NIL? {JB}} -> {NIL? {JB}} } _pfr Analysons la suite de remplacements pour {b '{NIL? NIL}} _pen Let's trace the text-rewriting process for {b '{NIL? NIL}} {{geek} {pre 0: '{NIL? NIL} 1: '{{lambda {:c} {:c !NIL}} NIL} 2: '{NIL !NIL} 3: '{{lambda {} TRUE} !NIL} 4: TRUE }} _pfr et {b '{NIL? {JB}}} _pen and {b '{NIL? {JB}}} {{geek} {pre 0: '{NIL? {JB}} 1: '{NIL? {PAIR James Bond}} 2: '{NIL? {{lambda {:a :b :c} {:c :a :b}} James Bond}} 3: '{NIL? {lambda {:c} {:c James Bond}}} 4: '{{lambda {:c} {:c !NIL}} {lambda {:c} {:c James Bond}}} 5: '{{lambda {:c} {:c James Bond}} !NIL} 6: '{!NIL James Bond} 7: '{{lambda {} FALSE} James Bond} 8: FALSE }} _pfr La vie n'est pas un long fleuve tranquille, en effet. Demandez à [[Stephen Wolfram|https://fr.wikipedia.org/wiki/Stephen_Wolfram]] ce qu'il en pense quand il joue avec les [[supercombinateurs|https://writings.stephenwolfram.com/2020/12/combinators-a-centennial-view/]]... _pen Life is not a long quiet river, indeed. Ask [[Stephen Wolfram|https://en.wikipedia.org/wiki/Stephen_Wolfram]] what he thinks about when he plays with [[supercombinators|https://writings.stephenwolfram.com/2020/12/combinators-a-centennial-view/]]... _h3fr arbres _h3en trees _pfr Notre langage qui ne connaissait initialement que les mots et les fonctions vient donc de s'enrichir de deux nouveaux éléments, les booléens et les paires. Avec les premiers on dispose d'un moyen de choisir entre deux mots et avec les secondes on peut agréger deux mots. Mais pas que ! Il se trouve qu'une paire est référencée par un mot - par exemple le mot {b JB} désigne la paire {b '{PAIR James Bond}} - et donc chaque terme d'une paire peut contenir une paire, dont chaque terme peut contenir une paire ... et ainsi de suite à l'infini. Nous venons de définir ce qu'on appelle un {b arbre binaire}. Par exemple : _pen Our language, which initially knew only words and functions, has just been enriched with two new elements, booleans and pairs. With the first ones we have a way to choose between two words and with the second ones we can aggregate two words. But not only! It turns out that a pair is referenced by a word - for example the word {b JB} designates the pair {b '{PAIR James Bond}} - and so each term of a pair can contain a pair, in which each term can contain a pair ... and so on ad infinitum. We have just defined what is called a {b binary tree}. For instance: {pre '{def BTREE {PAIR {PAIR {PAIR a b} {PAIR c d} } {PAIR {PAIR e f} {PAIR g h} } } } -> {def BTREE {PAIR {PAIR {PAIR a b} {PAIR c d} } {PAIR {PAIR e f} {PAIR g h} } } } } _pfr et bien sûr on pourra retrouver chaque élément de la paire en utilisant les "accesseurs" {b LEFT} et {b RIGHT}, par exemple _pen and of course we can find each element of the pair by using the accessors {b LEFT} and {b RIGHT}, for instance {pre '{LEFT {LEFT {LEFT {BTREE}}}} -> {LEFT {LEFT {LEFT {BTREE}}}} '{RIGHT {RIGHT {RIGHT {BTREE}}}} -> {RIGHT {RIGHT {RIGHT {BTREE}}}} } _pfr Les arbres binaires sont omni-présents dans les langages informatiques et méritent à eux seuls un long développement. Mais dans cette page nous nous intéresserons à un type particulier d'arbre binaire, un arbre "dégénéré", la {b liste}. _pen Binary trees are omnipresent in computer languages and deserve a long development on their own. But in this page we will focus on a particular type of binary tree, a "degenerate" tree, the {b list}. _h3fr listes _h3en lists _pfr Une {b liste} est une paire dont le terme de gauche est un {b mot} et le terme de droite est une {b paire} ou {b NIL}. Noter qu'il s'agit d'une définition {b récursive}, une liste contient une liste qui contient une liste, et ainsi de suite jusqu'à la liste vide, {b NIL}. Voici comment on construit une liste de 4 mots : _pen A {b list} is a pair whose left term is a {b word} and right term is a {b pair} or {b NIL}. Note that this is a {b recursive} definition, a list contains a list that contains a list, and so on until the empty list, {b NIL}. This is how can be built a list of 4 words: {pre '{def LIST {PAIR Hello {PAIR brave {PAIR new {PAIR World NIL}}}}} -> {def LIST {PAIR Hello {PAIR brave {PAIR new {PAIR World NIL}}}}} } _pfr Les termes de la liste peuvent être extraits manuellement _pen The terms from the list can be extracted manually {pre '{LEFT {LIST}} Hello (brave new World NIL) -> {LEFT {LIST}} '{LEFT {RIGHT {LIST}}} brave (new World NIL) -> {LEFT {RIGHT {LIST}}} '{LEFT {RIGHT {RIGHT {LIST}}}} new (World NIL) -> {LEFT {RIGHT {RIGHT {LIST}}}} '{LEFT {RIGHT {RIGHT {RIGHT {LIST}}}}} World (NIL) -> {LEFT {RIGHT {RIGHT {RIGHT {LIST}}}}} '{RIGHT {RIGHT {RIGHT {RIGHT {LIST}}}}} NIL -> {RIGHT {RIGHT {RIGHT {RIGHT {LIST}}}}} } _pfr Mais on aimerait pouvoir automatiser ce processus. A chaque étape testons la liste avec la fonction {b NIL?} _pen But we would like to automate this process. At each step let's test the list with the function {b NIL?} {pre '{NIL? {LIST}} (Hello brave new World NIL) -> {NIL? {LIST}} '{NIL? {RIGHT {LIST}}} (brave new World NIL) -> {NIL? {RIGHT {LIST}}} '{NIL? {RIGHT {RIGHT {LIST}}}} (new World NIL) -> {NIL? {RIGHT {RIGHT {LIST}}}} '{NIL? {RIGHT {RIGHT {RIGHT {LIST}}}}} (World NIL) -> {NIL? {RIGHT {RIGHT {RIGHT {LIST}}}}} '{NIL? {RIGHT {RIGHT {RIGHT {RIGHT {LIST}}}}}} (NIL) -> {NIL? {RIGHT {RIGHT {RIGHT {RIGHT {LIST}}}}}} } _pfr Il se trouve que toutes ces manipulations peuvent être condensées en une seule fonction _pen It happens that all these manipulations can be condensed in a single function {pre '{def L.DISP {lambda {:list} {{IF {NIL? :list} {lambda {:list} } {lambda {:list} {LEFT :list} {L.DISP {RIGHT :list}}}} :list}}} -> {def L.DISP {lambda {:l} {{IF {NIL? :l} {lambda {:l} } {lambda {:l} {LEFT :l} {L.DISP {RIGHT :l}}}} :l}}} '{L.DISP {LIST}} -> {L.DISP {LIST}} } _pfr Le corps de la fonction est une structure de test choisissant entre deux lambdas. Lorsqu'elle reçoit une liste, {b :list}, elle la teste avec {b '{NIL? :list}} : _lfr si la liste est réduite à NIL elle retourne une lambda qui ne fait rien, _lfr sinon elle retourne une lambda qui affiche le terme de gauche de la liste , {b '{LEFT :list}}, et {b recommence} le même processus sur le reste de la liste, {b '{L.DISP {RIGHT :list}}}. _pen The function' body is a test structure choosing between two lambdas. When it receives a list, {b :list}, it tests it with {b '{NIL? :list}}: _len if the list is reduced to NIL it returns the first lambda which does nothing, _len otherwise it returns the second lambda which displays the left term of the list, {b '{LEFT :list}}, and {b starts again} the same process on the rest of the list, {b '{L.DISP {RIGHT :list}}}. _pfr On a ainsi appliqué une {b boucle récursive} sur une structure de données récursive. Quoi de plus naturel ? Et oui, notre bébé langage vient de se doter de {b boucles}. _pen We have thus applied a {b recursive loop} on a recursive data structure. What could be more natural? And yes, our babby language has got {b loops}. _pfr Ce premier exemple est fondamental et servira de {b modèle de boucle} à tout ce qui suit. Voici par exemple une fonction concatenant deux listes _pen This first example is fundamental and will serve as a {b loop model} for everything that follows. For example, here is a function concatenating two lists {pre '{def CONCAT {lambda {:l1 :l2} {{IF {NIL? :l1} {lambda {:l1 :l2} :l2} {lambda {:l1 :l2} {PAIR {LEFT :l1} {CONCAT {RIGHT :l1} :l2}}} } :l1 :l2}}} -> {def CONCAT {lambda {:l1 :l2} {{IF {NIL? :l1} {lambda {:l1 :l2} :l2} {lambda {:l1 :l2} {PAIR {LEFT :l1} {CONCAT {RIGHT :l1} :l2}}} } :l1 :l2}}} '{def LIST1 {PAIR a {PAIR b {PAIR c NIL}}}} -> {def LIST1 {PAIR a {PAIR b {PAIR c NIL}}}} '{def LIST2 {PAIR d {PAIR e {PAIR f {PAIR g NIL}}}}} -> {def LIST2 {PAIR d {PAIR e {PAIR f {PAIR g NIL}}}}} '{L.DISP {CONCAT {LIST1} {LIST2}}} -> {L.DISP {CONCAT {LIST1} {LIST2}}} } _pfr La page [[coding]] montre comment on peut construire sur le concept de liste l'ensemble des nombres naturels positifs et les opérateurs liés [{b + - * / %}]. La page [[big numbers|?view=oops6]] montre comment on peut calculer sur des nombres de grande taille, par exemple _pen The page [[coding]] shows how to build on the concept of list the set of positive natural numbers and the related operators [{b + - * / %}]. The [[big numbers|?view=oops6]] page shows how we can compute on big numbers, for example {pre fibonacci(100) = 354224848179261915075 factorial(22) = 1124000727777607680000 } _pfr en utilisant des listes de booléens. Rien d'autre que des combinaisons de plus en plus profondes de simples remplacements de texte. _pen using lists of booleans. Nothing but deeper and deeper combinations of simple text replacements. _h3fr les tours de hanoï _h3en towers of hanoï _img https://upload.wikimedia.org/wikipedia/commons/thumb/e/e8/AnimeHanoiNB.gif/440px-AnimeHanoiNB.gif _pfr Comme application simple et remarquable du concept de liste voici le jeu des {b Tours de Hanoï}, (voir détails dans [[hanoi4]]). Plusieurs disques de taille décroissante sont empilés sur une tige {b A}. Le jeu consiste à déplacer chaque disque sur une deuxième tige {b B} via une troisième {b C} en respectant la règle suivante : "{i ne jamais mettre un disque sur un plus petit}". Le code est construit sur une fonction doublement récursive. _pen As a simple and remarkable application of the list concept here is the game of {b Towers of Hanoi}, (see details in [[hanoi]] and [[concepts3]]). Several disks of decreasing size are stacked on a rod {b A}. The game consists in moving each disk on a second stem {b B} via a third one {b C}, respecting the following rule: "{i never put a disk on a smaller one}". The code is built on a double recursive function. {pre '{def HANOI {lambda {:n :a :b :c} {{IF {NIL? :n} {lambda {:n :a :b :c} } {lambda {:n :a :b :c} {HANOI {RIGHT :n} :a :c :b} {br} move {LEFT :n} from tower :a to tower :b {HANOI {RIGHT :n} :c :b :a} }} :n :a :b :c}}} -> {def HANOI {lambda {:n :from :to :via} {{IF {NIL? :n} {lambda {:n :from :to :via} } {lambda {:n :from :to :via} {HANOI {RIGHT :n} :from :via :to} {div} move {b {LEFT :n}} from tower :from to tower :to {HANOI {RIGHT :n} :via :to :from} }} :n :from :to :via}}} } _pfr Nous supposerons ici qu'il y a 4 disques, {b n=4}, représentés par les termes de la liste {code (■■■■.■■■■ ■■■.■■■ ■■.■■ ■.■))}. _pen We will assume here that there are 4 disks, {b n=4}, represented by the terms in the list {code (■■■■.■■■■ ■■■.■■■ ■■.■■ ■.■)}. {pre '{HANOI {PAIR ■■■■.■■■■ {PAIR ■■■.■■■ {PAIR ■■.■■ {PAIR ■.■ NIL}}}} A B C} -> {HANOI {PAIR ■■■■.■■■■ {PAIR ■■■.■■■ {PAIR ■■.■■ {PAIR ■.■ NIL}}}} A B C} } _pfr Sans autres explicationsm, (voir [[coding]]), il faut savoir qu'il existe une fonction extrêmement simple, appelée le {b Ω-combinateur} _pen Without further explanationm, (see [[coding]]), you should know that there is an extremely simple function, called the {b Ω-combinator} {pre '{def Ω {lambda {:g} {:g :g}}} -> {def Ω {lambda {:g} {:g :g}}} } _pfr grâce à laquelle on peut remplacer dans {b '{HANOI {LIST} A B C}} tous les noms par leurs lambda définitions. On aboutit à cette cascade de lambdas _pen thanks to which we can replace in {b '{HANOI {LIST} A B C}} all names by their lambda definitions. We end up with this cascade of lambdas {pre '{{{lambda {:g} {:g :g}} {lambda {:g :n :a :b :c} {{{lambda {:a :b :c} {:a :b :c}} {{lambda {:c} {:c {lambda {:a :b} {lambda {:a :b} :b}}}} :n} {lambda {:g :n :a :b :c} } {lambda {:g :n :a :b :c} {:g :g {{lambda {:c} {:c {lambda {:a :b} :b}}} :n} :a :b :c} {br} move {{lambda {:c} {:c {lambda {:a :b} :a}}} :n} from tower :a to tower :b {:g :g {{lambda {:c} {:c {lambda {:a :b} :b}}} :n} :c :b :a} }} :g :n :a :b :c}}} {{lambda {:a :b :c} {:c :a :b}} ■■■■.■■■■ {{lambda {:a :b :c} {:c :a :b}} ■■■.■■■ {{lambda {:a :b :c} {:c :a :b}} ■■.■■ {{lambda {:a :b :c} {:c :a :b}} ■.■ {lambda {:a} {lambda {:a :b} :a}}}}}} A B C} } _pfr produisant bien sûr le même résultat et qui montre que tout cela n'est qu'une composition profonde de remplacements de texte. Où la frontière entre données et code devient difficile à trouver, certains lui ont donné un nom : {b homoiconicité}. Rien d'autre que l'application systématique de cette "{b IIFE}" _pen producing of course the same result and showing that all this is only a deep composition of text replacements. Where the border between data and code becomes difficult to find, some have given it a name: {b homoiconicity}. Nothing else than the systematic application of this "{b IIFE}". {pre '{{lambda {words} expression} words} } _pfr Il est étonnant qu'on puisse faire tant avec si peu, non ? _pen It's amazing how much you can do with so little, isn't it? } {{block} {uncover http://colette.cerda.free.fr/coco.c/data/e_pf1.jpg 100 500 ORCHESTRE.3{div}encre monotype sur papier 18x24cm{div}colette} _h2fr lambda{sup talk} _h2en lambda{sup talk} _pfr Dans la section précédente nous avons mis en évidence deux formes (dites) "spéciales", {b lambda & def}, la première essentielle et la seconde théoriquement optionnelle. Nous avons également supposé que le dictionnaire était vide de toute fonction existante prédéfinie, et nous avons commencé à le remplir en construisant {b HI, HBNWW, ..., TRUE, FALSE, IF, PAIR, LEFT, RIGHT, NIL, !NIL, NIL?, P.DISP, ..., P.SWAP, BTREE, LIST, L.DISP, CONCAT, HANOI, Ω}. Et théoriquement nous aurions pu continuer ainsi et coder tous les algorithmes possibles et imaginables. Théoriquement ! _pen In the previous section we highlighted two (so-called) "special" forms, {b lambda & def}, the first essential and the second theoretically optional. We also assumed that the dictionary was empty of any existing predefined functions, and we started filling it by constructing {b HI, HBNWW, ..., TRUE, FALSE, IF, PAIR, LEFT, RIGHT, NIL, !NIL, NIL?, P.DISP, ..., P.SWAP, BTREE, LIST, L.DISP, CONCAT, HANOI, Ω}. And theoretically we could have gone on like this and coded every conceivable algorithm. Theoretically! _h3fr lambdatalk au complet _h3en the full lambdatalk _pfr En fait lambdatalk est équipé de neuf formes spéciales _pen In fact lambdatalk is equipped with nine special forms {pre {@ style="text-align:center;"} lambda, def, if, let, quote, macro, style, script, require } _pfr et son dictionnaire contient près de 200 primitives, c'est à dire des fonctions prédéfinies écrites dans le langage du navigateur hôte, Javascript. Vous pouvez cliquer sur le museau d'Amélie Poulain pour les afficher : _pen and its dictionary contains nearly 200 primitives, i.e. predefined functions written in the host browser language, Javascript. You can click on Amélie Poulain's snout to display them: {uncover data/amelie_poulain.jpg 100 500 {prewrap [unquote, include, lib, @, 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, svg, line, rect, circle, ellipse, polygon, polyline, path, text, g, mpath, use, textPath, pattern, image, clipPath, defs, animate, set, animateMotion, animateTransform, title, desc, input, iframe, hide, prewrap, +, *, -, /, %, <, >, <=, >=, =, not, or, and, abs, acos, asin, atan, ceil, cos, exp, floor, pow, log, random, round, sin, sqrt, tan, min, max, PI, E, date, W.equal?, W.empty?, W.length, W.get, W.first, W.rest, W.last, W.slice, W.reverse, W.sort, W.lib, 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, 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.swap!, A.lib, P.new, cons, P.pair?, P.left, car, P.right, cdr, P.disp, P.lib, LS.display, LS.setItem, LS.getItem, LS.removeItem, LS.clear, show_last_code, turtle, long_add, long_mult, uncover, drag, editable] }} _pfr Cette boite à outils va nous permettre de simplifier considérablement notre code. Dans ce qui suit nous allons donc reprendre les grandes étapes des deux sections précédentes. _pen This toolbox will allow us to simplify our code considerably. In the following we will repeat the main steps of the two previous sections. _h3fr booléens _h3en booleans _pfr Nous avions défini trois fonctions, {b TRUE, FALSE, IF} travaillant conjointement. Il n'est plus besoin de les construire, les booléens sont prédéfinis, {b true & false}, pratiquement comme les nombres {b 1 & 0}. Reprenons l'exemple de la section précédente en utilisant la troisième forme spéciale {b '{if bool then ... else ...}}. _pen We had defined three functions, {b TRUE, FALSE, IF} working together. There is no need to build them anymore, the booleans are predefined, {b true & false}, almost like the numbers {b 1 & 0}. Let's take the example from the previous section and use the third special form {b '{if bool then ... else ...}}. {pre '{if true then James else Bond} -> {if true then James else Bond} '{if false then James else Bond} -> {if false then James else Bond} '{if true then Nicolas else de Caritat de Condorcet} -> {if true then Nicolas else de Caritat de Condorcet} '{if false then Nicolas else de Caritat de Condorcet} -> {if false then Nicolas else de Caritat de Condorcet} } _pfr où {b then} et {b else} sont deux mots-clé du langage servant de séparateur entre les deux termes, qui ne sont plus réduits à des mots simples. _pen where {b then} and {b else} are two key words of the language serving as a separator between the two terms, which are no longer reduced to single words. _pfr Rien de bien compliqué. Mais nous ne chercherons pas ici (et par la suite) à "comprendre" l'évaluation de ces expressions, à remplacer par exemple {b true} par son éventuelle lambda expression équivalente, à "tracer" les "remplacements de texte". Ce n'est plus possible, tout est maintenant caché sous le "capot". C'est très bien dans la vie de tous les jours mais frustrant quand il s'agit de comprendre les comportements parfois "magiques" des formes spéciales et des primitives. C'est la raison pour laquelle il me paraît si essentiel de commencer au niveau le plus bas où rien n'existe et tout est à construire et de bien comprendre les fondations ultimes du processus d'évaluation. _pen Nothing very complicated. But we will not try here (and later) to "understand" the evaluation of these expressions, to replace for example {b true} by its possible lambda equivalent expression, to "trace" the "text replacements". This is no longer possible, everything is now hidden under the "hood". This is fine in everyday life but frustrating when it comes to understanding the sometimes "magical" behavior of special forms and primitives. This is why I think it is so essential to start at the lowest level where nothing exists and everything is to be built and to understand the ultimate foundations of the evaluation process. _pfr Nous allons rapidement étudier des exemples plus intéressants. _pen We will quickly look at some more interesting examples. _h3fr paires _h3en pairs _pfr Dans le dictionnaire de lambdatalk nous découvrons un ensemble de fonctions traitant les paires _pen In the lambdatalk dictionary we discover a set of functions dealing with the pairs {pre '{P.lib} -> PAIR: [8] [P.new, P.pair?, P.left, P.right, P.disp, P.lib] } _pfr avec lesquelles nous allons sans plus d'explications ré-écrire les exemples de la section précédente _pen with which we will without further explanation rewrite the examples of the previous section {pre '{def jb {P.new James Bond}} -> {def jb {P.new James Bond}} '{P.left {jb}} -> {P.left {jb}} '{P.right {jb}} -> {P.right {jb}} '{P.disp {jb}} -> {P.disp {jb}} '{P.pair? {jb}} -> {P.pair? {jb}} '{P.pair? nil} -> {P.pair? nil} } {hr} _h3fr récursion _h3en recursion _pfr Nous avons bien noté que le codes de la fonction {b L.DISP} restait assez confus avec ses deux lambdas internes, dont le but est de protéger le contenu d'une évaluation précoce. C'est bien l'avantage de la troisième forme spéciale, {b if then else}, qui cache tout ce mécanisme sous le capot et permet d'écrire un code bien plus lisible. _pen We did note that the code of the {b L.DISP} function remained rather confusing with its two internal lambdas, whose purpose is to protect the content from early evaluation. This is the advantage of the third special form, {b if then else}, which hides all this mechanism under the hood and allows to write a much more readable code. _pfr Utilisant les primitives créant et manipulant les paires nous définissons une liste de quatre disques _pen Using the primitives creating and manipulating pairs we define a list of four disks {pre '{def discs {P.new ■■■■.■■■■ {P.new ■■■.■■■ {P.new ■■.■■ {P.new ■.■ \}}}}} // where \ is any simple word -> {def discs {P.new ■■■■.■■■■ {P.new ■■■.■■■ {P.new ■■.■■ {P.new ■.■ nil}}}}} } _pfr et une fonction {b disp} affichant ses termes _pen and a function {b disp} displaying its terms {pre '{def disp {lambda {:list} {if {not {P.pair? :list}} then else {P.left :list} {disp {P.right :list}}}}} -> {def disp {lambda {:list} {if {not {P.pair? :list}} then else {P.left :list} {disp {P.right :list}}}}} '{disp {discs}} -> {disp {discs}} } _pfr dont le code est nettement simplifié, débarrassé des lambda internes. _pen whose code is clearly simplified, free of internal lambda. _pfr On peut faire de même pour la fonction {b HANOI}, épurée autant que faire se peut _pen We can do the same for the function {b HANOI}, purified as much as possible {pre '{def hanoi {lambda {:discs :a :b :c} {if {not {P.pair? :discs}} then else {hanoi {P.right :discs} :a :c :b} {div}move {P.left :discs} from tower :a to tower :b {hanoi {P.right :discs} :c :b :a} }}} -> {def hanoi {lambda {:discs :a :b :c} {if {not {P.pair? :discs}} then else {hanoi {P.right :discs} :a :c :b} {div} move {b {P.left :discs}} from tower :a to tower :b {hanoi {P.right :discs} :c :b :a} }}} '{hanoi {discs} A B C} -> {hanoi {discs} A B C} } _pfr Comme dernier exemple voici comment dessiner un tapis de Sierpinsky écrit à l'aide de deux primitives, {b S.replace & S.map}. _pen As a last example this is how to draw a [[Sierpinsky's carpet|?view=sierpinsky_compare]] written with two primitives, {b S.replace & S.map}. {pre '{def sierpinsky {def sierpinsky.r {lambda {:n :w} {if {= :n 0} then :w else {sierpinsky.r {- :n 1} {S.map {lambda {:x} :x:x:x} :w} {S.map {lambda {:x} :x{S.replace ■ by o in :x}:x} :w} {S.map {lambda {:x} :x:x:x} :w} }}}} {lambda {:n} {h3 S:n}{S.replace o by space in {S.replace \s by {div} in {sierpinsky.r :n ■}}}{div}}} -> {def sierpinsky {def sierpinsky.r {lambda {:n :w} {if {= :n 0} then :w else {sierpinsky.r {- :n 1} {S.map {lambda {:x} :x:x:x} :w} {S.map {lambda {:x} :x{S.replace ■ by o in :x}:x} :w} {S.map {lambda {:x} :x:x:x} :w} }}}} {lambda {:n} {h3 S:n}{div .}{S.replace o by space in {S.replace \s by {div} in {sierpinsky.r :n ■}}}{div .}}} '{S.map sierpinsky 0 1 2 3} -> } _pfr dont le résultat est la longue séquence formatée de caractères {b ■} ci-dessous _pen whose result is the following long formated sequence of chars {b ■} {pre {@ style='font-family:monaco; line-height:0.6em;'} {S.map sierpinsky 0 1 2 3} } _pfr Oui, il s'agit bien d'une séquence de {b caractères, ■,} et non d'images. _pen Yes, it's a sequence of {b words, ■,} and not pictures. _pfr Vous vous demandez peut-être ce qu'il en est des {b IIFE} dans ce lambdatalk complet ? _pen You may be wondering about the {b IIFE} in this complete lambdatalk? _h3 let _pfr Il existe une quatrième forme spéciale, {b let}, un "sucre syntaxique" permettant d'écrire par exemple cette IIFE _pen There is a third special form, {b let}, a "syntactic sugar" allowing to write for example {pre '{{lambda {:a :b} My name is :b, :a :b.} James Bond} } _pfr sous une forme mettant mieux en évidence le lien entre les variables et leurs valeurs _pen in a form that better highlights the relationship between the variables and their values {pre '{let { {:a James} {:b Bond} } My name is :b, :a :b. } } _pfr On a donc défini deux variables locales, {b :a & :b}, on leur a affecté deux valeurs, {b James & Bond}, et on a écrit l'expression {b My name is :b, :a :b.} dans un contexte local dans lequel elles sont parfaitement définies. _pen So we defined two local variables, {b :a & :b}, assigned them two values, {b James & Bond}, and wrote the expression {b My name is :b, :a :b.} in a local context where they are perfectly defined. _pfr Autre exemple _pen Another example {pre '{let { {:fr {lambda {:a :b} Je m'appelle :b, :a :b.}} {:en {lambda {:a :b} My name is :b, :a :b.}} {:es {lambda {:a :b} Mi nombre es :b, :a :b.}} {:de {lambda {:a :b} Ich heiße :b, :a :b.}} {:it {lambda {:a :b} Il mio nome è :b, :a :b.}} {:ru {lambda {:a :b} Меня зовут :b, :a :b.}} } {br}{:fr Brigitte Bardot} {br}{:en Jane Birkin} {br}{:de Romy Schneider} {br}{:es Penelope Cruz} {br}{:it Monica Bellucci} {br}{:ru Сергей Рахманинов} } -> {let { {:fr {lambda {:a :b} Je m'appelle :b, :a :b.}} {:en {lambda {:a :b} My name is :b, :a :b.}} {:es {lambda {:a :b} Mi nombre es :b, :a :b.}} {:de {lambda {:a :b} Ich heiße :b, :a :b.}} {:it {lambda {:a :b} Il mio nome è :b, :a :b.}} {:ru {lambda {:a :b} Меня зовут :b, :a :b.}} }
{:fr Brigitte Bardot}
{:en Jane Birkin}
{:de Romy Schneider}
{:es Penelope Cruz}
{:it Monica Bellucci}
{:ru Сергей Рахманинов} } } _pfr dans lequel on a défini plusieurs fonctions locales, évitant ainsi la "pollution" du dictionnaire. _pen n which we have defined several local functions, thus avoiding the "pollution" of the dictionary. °°° _pfr Les formes {b let} peuvent être emboitées et on peut de même réécrire la fonction {b L.DISP}, décomposant son fonctionnement en plusieurs étapes plus simples à suivre _pen The {b let} forms can be nested and the {b L.DISP} function can be rewritten in the same way, breaking down its operation into several steps that are easier to follow {pre '{def DISP {lambda {:list} {let { {:list :list} {:stop {lambda {:list} }} {:recurse {lambda {:list} {LEFT :list} {DISP {RIGHT :list}}}} } {let { {:list :list} {:fork {IF {NIL? :list} :stop :recurse}} } {:fork :list} }}}} -> {def DISP {lambda {:l} {let { {:l :l} {:stop {lambda {:l} }} {:recurse {lambda {:l} {LEFT :l} {DISP {RIGHT :l}}}} } {let { {:l :l} {:fork {IF {NIL? :l} :stop :recurse}} } {:fork :l} }}}} '{DISP {LIST}} -> {DISP {LIST}} } {{geek} _pfr {b Note} Détaillons cette fonction {b DISP} : _pen {b Note} Let's detail this {b DISP} function: _lfr 1) dans le premier contexte local _len 1) in the first local context _l20fr 1.1) on redéfinit le nom de la liste, _l20en 1.1) we redefine the list's name _l20fr 1.2) on appelle {b :stop} la fonction vide appelée en fin de boucle _l20en 1.2) we call {b :stop} the empty function called at the end of the loop, _l20fr 1.3) et {b :recurse} la fonction qui affiche le premier terme de la liste et s'appelle elle-même sur le reste de la liste, _l20en 1.3) and {b :recurse} the function that displays the first term of the list and calls itself on the rest of the list, _lfr dans le second contexte local _len 1) in the second local context _l20fr 2.1) on redéfinit le nom de la liste, _l20en 2.1) we redefine the list's name _l20fr 2.2) on appelle {b :fork} la fonction qui assure le branchement vers la sortie, {b :stop}, ou la récursion, {b :recurse}, en fonction du résultat du test {b '{NIL? :l}} _l20en 2.2) we call {b :fork} the function which ensures the branching towards the output, {b :stop}, or the recursion, {b :recurse}, according to the result of the test {b '{NIL? :l}} _l20fr 2.3) une fois choisi le nom {b :stop} ou {b :recurse} est appliqué à {b :l} afin de retourner le résultat. _l20en 2.3) once chosen the name {b :stop} or {b :recurse} is applied to {b :l} to return the result. _pfr Sachant que la forme spécial {b let} n'est qu'un sucre syntaxique de {b '{{lambda {words} expression} words}} et qu'une lambda n'a aucun accès à son environnement, il est nécessaire de redéfinir à chaque fois les variables du contexte local englobant. _pen Knowing that the special form {b let} is only a syntactic sugar of {b '{{lambda {words} expression} words}} and that a lambda has no access to its environment, it is necessary to redefine each time the variables of the surrounding local context. } °°° _pfr De façon générale la forme spéciale {b let} _pen In general, the special form {b let} {pre '{let { {:var1 val1} {:var2 val2} {:var3 val3} ... } expression } } _pfr est à rapprocher de la syntaxe utilisée dans les langages impératifs comme ici en Javascript _pen is similar to the syntax used in imperative languages like here in Javascript {pre let var1 = val1, var2 = val2, var3 = val3, ... ; instruction_1; instruction_2; ... } _pfr Une simple affaire de choix _pen A simple matter of choice } {{block} {uncover http://colette.cerda.free.fr/coco.c/data/e2_bvl232.jpg 100 500 ORCHESTRE.3{div}encre monotype sur papier 18x24cm{div}colette} _h2 conclusion _pfr {i Pas facile tout ça, je vous l'accorde.} _pen {i Not easy, I grant you.} _pfr Mais en quelques lignes bon nombre des définitions et concepts évoqués en début de page ont été introduits, même si ce fut sans toujours entrer dans les détails. D'autres pages du wiki les donnent en long et en large, au risque de lasser. _pen But in a few lines many of the definitions and concepts mentioned at the beginning of the page have been introduced, even if without always going into detail. Other pages of the wiki give them at length, at the risk of being boring. _pfr Lambdatalk est un langage fonctionnel en ce sens que tous les objets que nous avons construits, structures de données et de contrôle, sont définissables à l'aide d'une seule forme spéciale, {b lambda}, les trois autres, {b def let if}, n'étant que des "sucres syntaxiques" destinés à faciliter l'écriture et la lecture du code, et pour la dernière d'en améliorer l'efficacité. _pen Lambdatalk is a functional language in the sense that all the objects we have built, data and control structures, are definable with only one special form, {b lambda}, the three others, {b def let if}, being only "syntactic sugars" intended to facilitate the writing and reading of the code, and for the last one to improve its efficiency. _pfr Il faut noter qu'à ce stade les nombres n'existent pas, nous n'avons jamais manipulé que des mots. Il ne s'agit que de remplacement de texte. D'autres pages du wiki montrent comment construire une arithmétique sans faire appel aux objets mathématiques Javascript. D'autres encore explorent le langage complet, où les nombres sont manipulables à l'infini, des algorithmes complexes sont explorés, comme les algorithmes de [[tri rapide|?view=Lsort]], la [[transformée rapide de Fourier|?view=fft]] ou l'algorithme de [[de Casteljau|?view=casteljau2]]. _pen It should be noted that at this stage numbers do not exist, we have only ever manipulated words. It is only about text replacement. Other wiki pages show how to build arithmetic without using Javascript mathematical objects. Still others explore the complete language, where numbers are infinitely manipulable, complex algorithms are explored, like [[fast sort|?view=Lsort]] algorithms, an interactive [[tablesort]], the [[fast Fourier transform|?view=fft]] or the [[de Casteljau algorithm|?view=casteljau2]], ... _pfr La page [[coding]] fournit des explications détaillées sur le fonctionnement du noyau de lambdatalk, le jeu de primitives agissant sur les mots, les chaines, les tableaux, les listes, ... et l'environnement de travail, {b lambdatank}, un wiki fonctionnant dans tout navigateur web, et donc sur tous les systèmes informatiques. _pen The [[coding]] page provides detailed explanations on how the lambdatalk core works, the set of primitives acting on words, strings, arrays, lists, ... and the working environment, {b lambdatank}, a wiki running in any web browser, and thus on all computer systems. _pfr On peut même dessiner de belles [[courbes cycliques|?view=cyclics]] changeant aléatoirement de forme _pen You can even draw beautiful [[cyclic curves|?view=cyclics]] randomly changing shape {div {@ id="cyclic"}} _pfr Et pour finir sachez que cette page est un {b programme lambdatalk}, le texte qui la compose est écrit en lambdatalk, les titres, les paragraphes, les images et bien sûr les exemples de code sont du code lambdatalk, évalué en temps réel. Vous pouvez sans risque entrer dans l'éditeur de la page (cliquez sur le mot {b concept} en haut et à gauche de la page) et modifier ce que vous voulez, tester les algorithmes, modifier les valeurs. Essayez donc. C'est en "bricolant" du code qu'on finit par le comprendre. _pen And finally you should know that this page is a {b program lambdatalk}, the text that composes it is written in lambdatalk, the titles, the paragraphs, the images and of course the code examples are lambdatalk code, evaluated in real time. You can safely enter the page editor (click on the word {b concept} at the top left of the page) and modify what you want, test the algorithms, modify the values. Just try it. It's by "tinkering" with the code that you'll eventually understand it. _pfr Et quand vous écrirez en Java ou en Python vous vous souviendrez peut-être des premiers contacts que vous avez eu, grâce à lambdatalk, avec les fonctions, booléens, les listes, la récursion et autres joyeusetés de l'art de coder, et ça devrait bien vous aider à mieux digérer ces langages puissants. _pen And when you write in Java or Python you may remember the first contacts you had, thanks to lambdatalk, with functions, booleans, lists, recursion and other joys of the art of coding, and that should help you to better digest these powerful languages. _pfr Donner l'envie d'aller plus loin sur des bases aussi simples que possible, c'était le but de ce papier. A vous de juger s'il est atteint. _pen To give the desire to go further on bases as simple as possible, it was the goal of this paper. It's up to you to judge if it has been achieved. _p {i alain marty | 2022/08/04 / 2023/02/24} _ul [[HN|https://news.ycombinator.com/item?id=41884148]] _ul [[little languages|https://chreke.com/little-languages.html]] _ul [[Maxwell's equations|http://lambdaway.free.fr/lambdawalks/index.php?view=maxwell]] } ;; coder's corner {macro _h(\d)fr ([^\n]+)\n to {h€1 {@ class="fr"}€2}} {macro _h(\d)en ([^\n]+)\n to {h€1 {@ class="en"}€2}} {macro _pfr ([^\n]+)\n to {p {@ class="fr"}€1}} {macro _pen ([^\n]+)\n to {p {@ class="en"}€1}} {macro _l([\d]*)fr ([^\n]+)\n to {ul {@ class="fr" style="margin-left:€1px;"} {li €2}}} {macro _l([\d]*)en ([^\n]+)\n to {ul {@ class="en" style="margin-left:€1px;"} {li €2}}} {{hide} {def block div {@ style="display:inline-block; width:600px; vertical-align:top; padding:5px; margin:30px; "}} {def geek blockquote {@ style="transform:rotate(-2deg); border:1px dashed; padding:10px;"}} {def toggle {input {@ type="button" value="french" onclick="toggle(this)" style="position:fixed; top:10px; left:10px; z-index:2; font:normal 1.0em courier; color:#fff; background:#f00; border:0; border-radius:30px; box-shadow:0 0 8px #fff; padding:5px 10px;" }}} {def toggle2 {input {@ type="button" value="horizontal" onclick="toggle2(this)" style="position:fixed; top:10px; right:10px; z-index:2; font:normal 1.0em courier; color:#fff; background:#f00; border:0; border-radius:30px; box-shadow:0 0 8px #fff; padding:5px 10px;" }}} {def draw_cyclic {lambda {:a :b} {{SVG 580} {g {AXES 580 580} {polyline {@ points="{S.map {cyclic :a :b} {S.serie -10 10 0.01}}" {stroke #fff 4}}}}} {center {b p(t) = e{sup it} + {sup 1}/{sub 2}e{sup A*it} + {sup i}/{sub 3}e{sup B*it},
where A = :a & B = :b}} }} {def cyclic {lambda {:a :b :t} {* 150 {+ {cos :t} {* {/ 1 2} {cos {* :a :t}}} {* {/ 1 -3} {sin {* -:b :t}}}}} {* 150 {+ {sin :t} {* {/ 1 2} {sin {* :a :t}}} {* {/ 1 3} {cos {* -:b :t}}}}} }} {def SVG {lambda {:h} svg {@ width="580px" height=":hpx" style="background:#444"} }} {def AXES {lambda {:w :h} {@ transform="translate({/ :w 2},{/ :h 2}) scale(1,-1)"} {line {@ x1="-{/ :w 2}:w" y1="0" x2="{/ :w 2}" y2="0" stroke="red" fill="transparent"}} {line {@ x1="0" y1="-{/ :h 2}" x2="0" y2="{/ :h 2}" stroke="green" fill="transparent"}} }} {def stroke {lambda {:col :w} stroke=":col" fill="transparent" stroke-width=":w" }} } {style body { background:#444; } #page_frame { border:0; background:transparent; width:600px; margin:auto; ;; margin-left:0; } #page_content { background:transparent; color:#fff; border:0; box-shadow:0 0 0; font:normal 1.2em optima; width:600px; ;; width:3600px; } .page_menu { background:transparent; color:#fff; } a { color:#f80; } pre { box-shadow:0 0 0px #000; padding:5px; background:#333; color:#fff; font:normal 1.0em courier new; } b { color:cyan; } h1 { font-size:4.0em; margin:0; color:#fff; } h2 { font-size:3.0em; margin:0; color:#fff; } h3 { font-size:1.5em; margin:0; color:#fff; } h4 { font-size:1.2em; margin:0; color:#fff; } code { font-style:bold; } .fr { display:none; } .en { display:block; } } {script var toggle = function(obj) { var frs = document.getElementsByClassName('fr'); var ens = document.getElementsByClassName('en'); if (obj.value==='english') { for (var i=0; i< frs.length; i++) frs[i].style.display="none"; for (var i=0; i< ens.length; i++) ens[i].style.display="block"; obj.value = 'français'; } else { for (var i=0; i< frs.length; i++) frs[i].style.display="block"; for (var i=0; i< ens.length; i++) ens[i].style.display="none"; obj.value = 'english'; } }; var toggle2 = function(obj) { if (obj.value==='vertical') { obj.value = 'horizontal'; document.getElementById('page_content').style.width = '600px'; document.getElementById('page_frame').style.margin = 'auto'; } else { obj.value = 'vertical'; document.getElementById('page_content').style.width = '3600px'; document.getElementById('page_frame').style.marginLeft = '0px'; } }; } {script var foo = function() { document.getElementById("cyclic").innerHTML = LAMBDATALK.eval_forms( "{draw_cyclic {floor {* 10 {random}}} {floor {* 5 {random}}}}") }; setTimeout( foo, 10 ) setInterval( foo, 2000 ) }
lambdaway v.20211111