{{cite web |url=http://julia.readthedocs.org/en/latest/manual/introduction/ |title=Introduction |work=The Julia Manual |publisher=Read the Docs |access-date=2016-12-10 |archive-...
L'interchangeabilité du code et des données confère à Lisp sa syntaxe immédiatement reconnaissable. Tout le code du programme est écrit sous forme d'expressions S , ou listes entre parenthèses. Un appel de fonction ou une forme syntaxique s'écrit sous forme de liste, avec le nom de la fonction ou de l'opérateur en premier, suivi des arguments ; par exemple, une fonction
John McCarthy a commencé à développer Lisp en 1958, alors qu'il travaillait au Massachusetts Institute of Technology (MIT). Il était motivé par le désir de créer un langage de programmation pour l'IA fonctionnant sur l' IBM 704 , car il pensait qu'« IBM semblait être un partenaire prometteur pour mener activement des recherches en intelligence artificielle » . Il s'est inspiré d' Information Processing Language (IPL) , également basé sur le traitement de listes, mais ne l'a pas utilisé car il était conçu pour un matériel différent et il trouvait un langage algébrique plus attrayant . Pour ces raisons, il a participé à la conception du Fortran List Processing Language (FLPL), implémenté sous forme de bibliothèque Fortran. Cependant, il n'en était pas satisfait car il ne prenait pas en charge la récursivité ni l'instruction conditionnelle moderne « si-alors-sinon » (un concept nouveau lors de l'introduction de Lisp)
La notation originale de McCarthy utilisait des « expressions M » entre crochets, qui étaient traduites en expressions S. Par exemple, l'expression M MLisp par Horace Enea et de CGOL par Vaughan Pratt .
Lisp a été implémenté pour la première fois par Steve Russell sur un ordinateur IBM 704 à l'aide de cartes perforées . Russell travaillait pour McCarthy à l'époque et réalisa (à la surprise de McCarthy) que la fonction eval de Lisp pouvait être implémentée en code machine .
Selon McCarthy
Steve Russell a dit : « Écoutez, pourquoi ne pas programmer cette fonction d'évaluation ? » Je lui ai répondu : « Oh là là, vous confondez théorie et pratique ! Cette fonction est conçue pour la lecture, pas pour le calcul. » Mais il l'a fait quand même. Autrement dit, il a compilé la fonction d'évaluation de mon article en code machine IBM 704 , en corrigeant les bogues , puis l'a présentée comme un interpréteur Lisp, ce qu'elle était assurément. À ce moment-là, Lisp avait donc déjà la forme qu'on lui connaît aujourd'hui …
Le résultat fut un interpréteur Lisp fonctionnel qui pouvait être utilisé pour exécuter des programmes Lisp, ou plus précisément, pour « évaluer des expressions Lisp ».
Deux macros en langage assembleur pour l' IBM 704 sont devenues les opérations primitives de décomposition de listes : `car` ( contenu de la partie adresse du numéro de registre) et `cdr` ( contenu de la partie décrémentation du numéro de registre), les registres de l' unité centrale de traitement (CPU) de l'ordinateur. Les dialectes Lisp utilisent encore Communications de l'ACM le 1er avril 1960, intitulé « Fonctions récursives d'expressions symboliques et leur calcul par machine, partie I ». Il a montré qu'avec quelques opérateurs simples et une notation pour les fonctions anonymes empruntée à Church, on peut construire un langage Turing-complet pour les algorithmes.
Le premier compilateur Lisp complet, écrit en Lisp, a été implémenté en 1962 par Tim Hart et Mike Levin au MIT. Il pouvait être compilé en faisant simplement interpréter le code du compilateur par un interpréteur Lisp existant, produisant ainsi du code machine exécutable 40 fois plus rapidement que l'interpréteur. Ce compilateur a introduit le modèle Lisp de compilation incrémentale , dans lequel les fonctions compilées et interprétées peuvent s'entremêler librement. Le langage utilisé dans la note de service de Hart et Levin est beaucoup plus proche du style Lisp moderne que le code antérieur de McCarthy.
Dans les années 1980 et 1990, un effort considérable a été déployé pour unifier les travaux sur les nouveaux dialectes Lisp (principalement des successeurs de Maclisp tels que ZetaLisp et NIL (New Implementation of Lisp)) en un langage unique. Ce nouveau langage, Common Lisp , était partiellement compatible avec les dialectes qu'il remplaçait (l'ouvrage *Common Lisp the Language * souligne la compatibilité de diverses constructions). En 1994, l'ANSI a publié la norme Common Lisp, intitulée « ANSI X3.226-1994 Information Technology Programming Language Common Lisp ».
Depuis sa création, Lisp a été étroitement lié à la communauté de recherche en intelligence artificielle , notamment sur les systèmes PDP-10 . Lisp a servi à l'implémentation du langage Micro Planner , lui-même utilisé dans le célèbre système d'IA SHRDLU . Dans les années 1970, avec l'émergence de projets commerciaux liés à l'IA, les performances des systèmes Lisp existants sont devenues un enjeu majeur, les programmeurs devant maîtriser l'impact des différentes techniques et choix d'implémentation sur ces performances.
Généalogie et variantes
Au cours de ses soixante années d'existence, Lisp a donné naissance à de nombreuses variantes autour du principe fondamental d'un langage à expressions S. Certaines de ces variantes ont été standardisées et implémentées par différents groupes, chacun avec ses propres priorités (par exemple, Common Lisp et Scheme possèdent plusieurs implémentations). Cependant, dans d'autres cas, un projet logiciel définit un Lisp sans standardisation, et il n'existe pas de distinction claire entre le dialecte et l'implémentation (par exemple, Clojure et Emacs Lisp appartiennent à cette catégorie).
Les différences entre dialectes (et/ou implémentations) peuvent être très visibles ; par exemple, Common Lisp utilise le mot-clé `function` defunpour nommer une fonction, tandis que Scheme utilise `function` define. Au sein d'un dialecte standardisé, les implémentations conformes prennent en charge le même langage de base, mais avec des extensions et des bibliothèques différentes. Cela engendre parfois des différences notables par rapport au langage de base ; par exemple, Guile (une implémentation de Scheme) utilise define*`function` pour créer des fonctions pouvant avoir des arguments par défaut et/ou des arguments nommés , deux types d'arguments non standardisés.
LISP 1.5 – Première version largement diffusée, développée par McCarthy et d'autres au MIT. Elle porte ce nom car elle contenait plusieurs améliorations par rapport à l'interpréteur original « LISP 1 », mais ne constituait pas une restructuration majeure comme le serait le LISP 2 prévu.
Stanford LISP 1.6 – Successeur de LISP 1.5, développé au Stanford AI Lab et largement distribué sur les systèmes PDP-10 fonctionnant sous TOPS-10 . Il a été rendu obsolète par Maclisp et InterLisp.
Maclisp – développé pour le projet MAC du MIT , MACLISP est un descendant direct de LISP 1.5. Il fonctionnait sur les systèmes PDP-10 et Multics . MACLISP a ensuite été renommé Maclisp, et est souvent appelé MacLisp. Le terme « MAC » dans MACLISP n'a aucun lien avec le Macintosh d'Apple ni avec McCarthy .
Interlisp – développé chez BBN Technologies pour les systèmes PDP-10 fonctionnant sous TENEX , fut ensuite adopté comme Lisp « côte ouest » pour les machines Xerox Lisp sous le nom d’InterLisp-D. Une version allégée, appelée « InterLISP 65 », fut publiée pour les ordinateurs Atari 8 bits basés sur le processeur MOS Technology 6502. Maclisp et InterLisp étaient de sérieux concurrents.
muLISP – initialement développé par Albert D. Rich et David Stoutemeyer pour les petits systèmes micro-ordinateurs, il fut commercialisé en 1979. Fonctionnant alors sur des systèmes CP/M dotés de seulement 64 Ko de RAM, il fut ensuite porté sur MS-DOS. Le développement de cette dernière version s'acheva en 1995. Le logiciel mathématique « Derive » fut écrit en muLISP pour MS-DOS, puis pour Windows jusqu'en 2007.
ZetaLisp , également appelé Lisp Machine Lisp, était utilisé sur les machines Lisp et était un descendant direct de Maclisp. ZetaLisp a eu une grande influence sur Common Lisp.
LeLisp est un dialecte Lisp français. L'un des premiers constructeurs d'interface (appelé SOS Interface ) a été écrit en LeLisp.
Common Lisp (1984), tel que décrit dans l'ouvrage « Common Lisp the Language » , est une consolidation de plusieurs tentatives divergentes (ZetaLisp, Spice Lisp , NIL et S-1 Lisp ) visant à créer des dialectes successeurs de Maclisp , avec des influences substantielles du dialecte Scheme. Cette version de Common Lisp était disponible pour de nombreuses plateformes et a été acceptée par beaucoup comme standard de facto jusqu'à la publication de la norme ANSI Common Lisp (ANSI X3.226-1994). Parmi les sous-dialectes les plus répandus de Common Lisp figurent Steel Bank Common Lisp (SBCL), CMU Common Lisp (CMU-CL), Clozure OpenMCL (à ne pas confondre avec Clojure !), GNU CLisp et les versions ultérieures de Franz Lisp ; tous respectent la norme ANSI CL (voir ci-dessous).
EuLisp – tentative de développement d'un Lisp nouveau, efficace et épuré.
ISLISP – tentative de développer un nouveau Lisp efficace et propre. Normalisé comme ISO/IEC 13816:1997 et révisé plus tard comme ISO/IEC 13816:2007: Technologies de l'information – Langages de programmation, leurs environnements et interfaces de logiciels système – Langage de programmation ISLISP .
ANSI Common Lisp est une norme de l'American National Standards Institute (ANSI) pour Common Lisp, créée par le sous-comité X3J13 , mandaté pour s'appuyer sur le document de base Common Lisp : The Language et pour mener un processus de consensus public afin de trouver des solutions aux problèmes communs de portabilité des programmes et de compatibilité des implémentations de Common Lisp. Bien qu'il s'agisse formellement d'une norme ANSI, l'implémentation, la vente, l'utilisation et l'influence d'ANSI Common Lisp ont été et continuent d'être observées dans le monde entier.
ACL2, ou « A Computational Logic for Applicative Common Lisp », est une variante applicative (sans effets de bord) de Common Lisp. ACL2 est à la fois un langage de programmation capable de modéliser des systèmes informatiques et un outil permettant de démontrer les propriétés de ces modèles.
Après un certain déclin dans les années 1990, Lisp a connu un regain d'intérêt après 2000. La plupart des nouvelles activités se sont concentrées sur les implémentations de Common Lisp , Scheme , Emacs Lisp , Clojure et Racket , et comprennent le développement de nouvelles bibliothèques et applications portables.
De nombreux nouveaux programmeurs Lisp ont été inspirés par des auteurs tels que Paul Graham et Eric S. Raymond pour se consacrer à un langage que d'autres considéraient comme obsolète. Ces nouveaux programmeurs décrivent souvent Lisp comme une révélation et affirment être nettement plus productifs qu'avec d'autres langages. Cette prise de conscience accrue contraste avec le « hiver de l'IA » et le bref regain de popularité de Lisp au milieu des années 1990.
open source a créé de nouvelles infrastructures de soutien : CLiki est un wiki qui rassemble des informations sur Common Lisp ; le répertoire Common Lisp répertorie les ressources ; #lisp est un canal IRC populaire permettant le partage et le commentaire d’extraits de code (grâce à lisppaste, un bot IRC écrit en Lisp) ; Planet Lisp rassemble le contenu de divers blogs consacrés à Lisp ; sur LispForum , les utilisateurs discutent de sujets liés à Lisp ; Lispjobs est un service de publication d’offres d’emploi ; et il existe un service d’actualités hebdomadaire, Weekly Lisp News . Common-lisp.net héberge des projets open source Common Lisp. Quicklisp est un gestionnaire de bibliothèques pour Common Lisp.
Les cinquante ans de Lisp (1958-2008) ont été célébrés lors de l'événement LISP50@OOPSLA. Des réunions locales d'utilisateurs sont régulièrement organisées à Boston, Vancouver et Hambourg. Parmi les autres événements figurent la réunion européenne Common Lisp, le symposium européen Lisp et une conférence internationale sur Lisp.
La communauté Scheme maintient activement plus de vingt implémentations . Plusieurs implémentations importantes (Chicken, Gambit, Gauche, Ikarus, Larceny, Ypsilon) ont été développées dans les années 2000. La norme Scheme, le Revised 5 Report on the Algorithmic Language Scheme , a été largement adoptée par la communauté. Le processus Scheme Requests for Implementation a permis la création de nombreuses bibliothèques et extensions quasi-standard. Les communautés d'utilisateurs des différentes implémentations de Scheme continuent de croître. Un nouveau processus de normalisation a été lancé en 2003 et a abouti à la norme Scheme R6RS en 2007. L'utilisation de Scheme dans l'enseignement de l'informatique semble avoir quelque peu diminué. Certaines universités n'utilisent plus Scheme dans leurs cours d'introduction à l'informatique ; le MIT utilise désormais Python à la place de Scheme pour son programme de licence en informatique et son cours en ligne ouvert à tous (MOOC) MITx.
Il existe plusieurs nouveaux dialectes de Lisp : Arc , Hy , Nu , Liskell et LFE (Lisp Flavored Erlang). L’analyseur syntaxique de Julia est implémenté en Femtolisp, un dialecte de Scheme (Julia s’inspire de Scheme, qui est lui-même un dialecte de Lisp).
En octobre 2019, Paul Graham a publié une spécification pour Bel , « un nouveau dialecte de Lisp ».
Principaux dialectes
Common Lisp et Scheme représentent deux courants majeurs du développement Lisp. Ces langages reposent sur des choix de conception sensiblement différents.
Common Lisp succède à Maclisp . Ses principales influences sont Lisp Machine Lisp , Maclisp, NIL , S-1 Lisp , Spice Lisp et Scheme. Il reprend de nombreuses caractéristiques de Lisp Machine Lisp (un dialecte Lisp important utilisé pour programmer les machines Lisp ), mais a été conçu pour être implémenté efficacement sur n'importe quel ordinateur personnel ou station de travail. Common Lisp est un langage de programmation généraliste et possède donc une norme de langage étendue comprenant de nombreux types de données, fonctions, macros et autres éléments de langage intégrés, ainsi qu'un système objet ( Common Lisp Object System ). Common Lisp a également emprunté certaines fonctionnalités à Scheme, telles que la portée lexicale et les fermetures lexicales . Des implémentations de Common Lisp sont disponibles pour cibler différentes plateformes telles que LLVM , la machine virtuelle Java , x86-64, PowerPC, Alpha, ARM, Motorola 68000 et MIPS, et des systèmes d'exploitation tels que Windows, macOS, Linux, Solaris, FreeBSD, NetBSD, OpenBSD, Dragonfly BSD et Heroku.
Scheme est un dialecte statique et récursif terminal du langage de programmation Lisp, inventé par Guy L. Steele Jr. et Gerald Jay Sussman . Il a été conçu pour offrir une sémantique exceptionnellement claire et simple, ainsi qu'un nombre restreint de manières de formuler des expressions. Conçu une dizaine d'années avant Common Lisp, Scheme présente une conception plus minimaliste. Il possède un ensemble de fonctionnalités standard beaucoup plus réduit, mais avec certaines fonctionnalités d'implémentation (telles que l'optimisation des appels terminaux et les continuations complètes ) non spécifiées dans Common Lisp. Une grande variété de paradigmes de programmation, notamment les styles impératif, fonctionnel et à passage de messages, trouvent une expression aisée dans Scheme. Scheme continue d'évoluer grâce à une série de normes (le rapport révisé sur le langage algorithmique Scheme) et à une série de demandes d'implémentation Scheme (Scheme Requests for Implementation ).
Clojure est un dialecte de Lisp ciblant principalement la machine virtuelle Java (JVM ), le Common Language Runtime (CLR), la JVM Python , la JVM Ruby (YARV ) et la compilation en JavaScript . Il est conçu comme un langage pragmatique et généraliste. Clojure s'inspire fortement de Haskell et met l'accent sur l'immuabilité. Clojure permet d'accéder aux frameworks et bibliothèques Java, avec des annotations de type et une inférence de type optionnelles , afin que les appels à Java puissent éviter la réflexion et permettre des opérations rapides sur les types primitifs. Clojure n'est pas conçu pour être rétrocompatible avec les autres dialectes de Lisp.
De plus, les dialectes Lisp sont utilisés comme langages de script dans de nombreuses applications, les plus connus étant Emacs Lisp dans l' éditeur Emacs , AutoLISP puis Visual Lisp dans AutoCAD , Nyquist dans Audacity et Scheme dans LilyPond . La taille potentiellement réduite d'un interpréteur Scheme fonctionnel le rend particulièrement populaire pour les scripts embarqués. On peut citer comme exemples SIOD et TinyScheme , tous deux intégrés avec succès au logiciel de traitement d'images GIMP sous le nom générique de « Script-fu » . LIBREP, un interpréteur Lisp développé par John Harper et initialement basé sur le langage Emacs Lisp , a été intégré au gestionnaire de fenêtres Sawfish .
Lisp fut le premier langage où la structure du code est représentée fidèlement et directement dans une structure de données standard – une caractéristique plus tard qualifiée d’« homoiconicité ». Ainsi, les fonctions Lisp peuvent être manipulées, modifiées, voire créées au sein d’un programme Lisp sans manipulations de bas niveau. Ceci est généralement considéré comme l’un des principaux atouts du langage quant à sa puissance expressive, et le rend particulièrement adapté aux macros syntaxiques et à l’évaluation métacirculaire .
Lisp a profondément influencé Alan Kay , chef de l'équipe de recherche qui a développé Smalltalk au Xerox PARC ; et, à son tour, Lisp a été influencé par Smalltalk, les dialectes ultérieurs adoptant des fonctionnalités de programmation orientée objet (classes d'héritage, encapsulation d'instances, passage de messages, etc.) dans les années 1970. Le système d'objets Flavors a introduit le concept d' héritage multiple et le mixin . Le système d'objets Common Lisp offre l'héritage multiple, les multiméthodes avec dispatch multiple et les fonctions génériques de première classe , ce qui permet une forme flexible et puissante de dispatch dynamique . Il a servi de modèle à de nombreux systèmes d'objets Lisp ultérieurs (y compris Scheme ), souvent implémentés via un protocole de métaobjet , une conception méta-circulaire réflexive dans laquelle le système d'objets est défini en fonction de lui-même : Lisp était seulement le deuxième langage après Smalltalk (et reste l'un des très rares) à posséder un tel système de métaobjet. De nombreuses années plus tard, Alan Kay a suggéré qu'en raison de la confluence de ces caractéristiques, seuls Smalltalk et Lisp pouvaient être considérés comme des systèmes de programmation orientés objet correctement conçus.
Lisp a introduit le concept de ramasse-miettes automatique , dans lequel le système parcourt le tas à la recherche de mémoire inutilisée. Les progrès réalisés dans les algorithmes modernes et sophistiqués de ramasse-miettes, tels que le ramasse-miettes générationnel, ont été stimulés par son utilisation dans Lisp.
l'IA que Fortran et le langage C , issu d' ALGOL . Du fait de son aptitude aux applications complexes et dynamiques, Lisp a bénéficié d'un regain d'intérêt dans les années 2010.
Syntaxe et sémantique
Les exemples de cet article sont écrits en Common Lisp (bien que la plupart soient également valides en Scheme ).
Expressions symboliques (expressions S)
Lisp est un langage orienté expressions . Contrairement à la plupart des autres langages, aucune distinction n'est faite entre « expressions » et « instructions » ; tout le code et les données sont écrits sous forme d'expressions. Lorsqu'une expression est évaluée , elle produit une valeur (éventuellement plusieurs), qui peut ensuite être intégrée à d'autres expressions. Chaque valeur peut être de n'importe quel type de données.S-expressions , sexps), qui reflètent la représentation interne du code et des données ; et les méta-expressions ( M-expressions ), qui expriment des fonctions des S-expressions. Les M-expressions n'ont jamais été adoptées, et presque tous les Lisp actuels utilisent les S-expressions pour manipuler le code et les données.
L'utilisation des parenthèses est la différence la plus immédiatement visible entre Lisp et les autres familles de langages de programmation. De ce fait, les étudiants ont longtemps donné à Lisp des surnoms tels que « Perdu dans des parenthèses stupides » ou « Beaucoup de parenthèses superflues irritantes » . Cependant, la syntaxe des expressions S est également responsable d'une grande partie de la puissance de Lisp : sa simplicité et sa cohérence facilitent la manipulation par ordinateur. La syntaxe de Lisp ne se limite toutefois pas à la notation traditionnelle par parenthèses. Elle peut être étendue pour inclure des notations alternatives. Par exemple, XMLisp est une extension de Common Lisp qui utilise le protocole métaobjet pour intégrer les expressions S au langage XML (Extensible Markup Language ).
Le recours aux expressions confère au langage une grande flexibilité. Les fonctions Lisp étant écrites sous forme de listes, elles peuvent être traitées comme des données. Ceci facilite l'écriture de programmes manipulant d'autres programmes ( métaprogrammation ). De nombreux dialectes Lisp exploitent cette caractéristique grâce à des systèmes de macros, permettant ainsi une extension quasi illimitée du langage.
Listes
Une liste Lisp s'écrit avec ses éléments séparés par des espaces et entourés de parenthèses. Par exemple, ` list("1, ")` est une liste dont les éléments sont les trois atomes `a`, `b` et `c`. Ces valeurs sont implicitement typées : il s'agit respectivement de deux entiers et d'un type de données spécifique à Lisp appelé « symbole », et il n'est pas nécessaire de les déclarer comme tels.la notation préfixée . Le premier élément de la liste est le nom d'une fonction, d'une macro, d'une expression lambda ou d'un opérateur spécial (voir ci-dessous). Le reste de la liste correspond aux arguments. Par exemple, la fonction notation infixe serait " ".d'ALGOL . Les opérateurs arithmétiques en Lisp sont des fonctions variadiques (ou n-aires ), pouvant prendre un nombre quelconque d'arguments. Un opérateur d'incrémentation de style C, `++`, est parfois implémenté sous le nom incfde syntaxe appropriée.
) ( liste 3 4 "bar" ))
s'évalue à . Bien sûr, cela serait plus utile si une expression non triviale avait été substituée à la place de .)une évaluation court-circuitée et renvoient respectivement leur premier argument nul et non nul.
nul "jamais" ) "James" 'tâche 'temps )
sera évalué à « James ».
Expressions lambda et définition de fonction
Un autre opérateur spécial, ` fonction anonyme en lui passant la valeur 5.
Les fonctions nommées sont créées en stockant une expression lambda dans un symbole à l'aide de la macro defun.
types de données fondamentaux : les atomes et les listes. Une liste était une séquence ordonnée finie d'éléments, chaque élément étant soit un atome, soit une liste. Un atome pouvait être un nombre ou un symbole. Un symbole était essentiellement un élément unique nommé, représenté par une chaîne alphanumérique dans le code source , et utilisé soit comme nom de variable, soit comme donnée dans le traitement symbolique . Par exemple, la liste `a` contient trois éléments : le symbole `a` , la liste `b` et le nombre `2`.Cons-cell comme représentation iconographique omniprésente dans la littérature LISP.
Une liste Lisp est implémentée comme une liste simplement chaînée . Chaque cellule de cette liste est appelée un cons (en Scheme, une paire ) et est composée de deux pointeurs , appelés car et cdr . Ceux-ci sont respectivement équivalents aux champs liste chaînée .
Parmi les nombreuses structures de données pouvant être construites à partir de cellules cons, l'une des plus élémentaires est appelée liste propre . Une liste propre est soit le fonction d'ordre supérieur pour appliquer une fonction à la liste.
Du fait de l'omniprésence des listes et des boucles dans les systèmes Lisp, on croit souvent, à tort, qu'il s'agit des seules structures de données de Lisp. En réalité, presque tous les langages Lisp, à l'exception des plus simples, possèdent d'autres structures de données, comme les vecteurs ( tableaux ), les tables de hachage , les structures, etc.
Les expressions S représentent des listes
Diagramme en boîte et pointeur pour la liste (42 69 613)
Les expressions S entre parenthèses représentent des structures de listes chaînées. Il existe plusieurs façons de représenter une même liste sous forme d'expression S. Une liste `cons` peut s'écrire sous forme de paires pointées : `cons(car, cdr) ` , où `car` est la voiture et `cdr` le cdr. Une liste plus longue peut également s'écrire sous forme de paires pointées. On l'abrège généralement ` cons(car, cdr)` en notation de liste . Une liste impropre peut s'écrire en combinant les deux notations, comme pour la liste de trois `cons` dont le dernier cdr est `cdr` (c'est-à-dire la liste sous sa forme complète).paires cons , cette une complexité temporelle asymptotique O(n).
la programmation fonctionnelle évitent les fonctions destructives. Dans le dialecte Scheme, qui privilégie le style fonctionnel, les noms des fonctions destructives sont marqués d'un point d'exclamation, ou « bang », comme par exemple `set car bang` quasi-apostrophe en Scheme), saisi avec le \ `. Cet opérateur est presque identique à l'apostrophe simple, à la différence qu'il permet d'évaluer des expressions et d'interpoler leurs valeurs dans une liste entre guillemets grâce aux opérateurs de suppression de guillemets et d' insertion de guillemets . Si la variable a la valeur `a`, alors `a` est évalué à `a` , tandis que ` a` est évalué à `a` . L'apostrophe inversée est principalement utilisée pour définir les expansions de macros. Douglas Hofstadter (dans Gödel, Escher, Bach ) et d'autres comme un exemple de l' idée philosophique d' autoréférence .
Portée et clôture
La famille Lisp se divise quant à l'utilisation de la portée dynamique ou statique (ou lexicale) . Clojure, Common Lisp et Scheme utilisent par défaut la portée statique, tandis que newLISP , Picolisp et les langages intégrés à Emacs et AutoCAD utilisent la portée dynamique. Depuis la version 24.1, Emacs utilise à la fois la portée dynamique et la portée lexicale.
Structure de la liste du code du programme ; exploitation par les macros et les compilateurs
Une distinction fondamentale entre Lisp et les autres langages est que, dans Lisp, la représentation textuelle d'un programme est simplement une description lisible par l'homme des mêmes structures de données internes (listes chaînées, symboles, nombres, caractères, etc.) que celles utilisées par le système Lisp sous-jacent.
Lisp utilise ce système pour implémenter un système de macros très puissant. À l'instar d'autres langages de macros, comme celui défini par le préprocesseur C (le préprocesseur de macros des langages C , Objective-C et C++ ), une macro renvoie du code compilable. Cependant, contrairement aux macros du préprocesseur C, les macros Lisp sont des fonctions et peuvent donc exploiter toute la puissance de Lisp.
De plus, comme le code Lisp possède la même structure que les listes, les macros peuvent être construites à l'aide de n'importe quelle fonction de traitement de listes du langage. En bref, tout ce que Lisp peut faire à une structure de données, les macros Lisp peuvent le faire au code. À l'inverse, dans la plupart des autres langages, la sortie de l'analyseur syntaxique est purement interne à l'implémentation du langage et ne peut être manipulée par le programmeur.
Cette fonctionnalité facilite le développement de langages efficaces au sein d'autres langages. Par exemple, le système d'objets Common Lisp peut être implémenté proprement comme une extension du langage à l'aide de macros. Ainsi, si une application nécessite un mécanisme d'héritage différent, elle peut utiliser un système d'objets différent. Cela contraste fortement avec la plupart des autres langages ; par exemple, Java ne prend pas en charge l'héritage multiple et il n'existe aucun moyen simple de l'ajouter.
Dans les implémentations Lisp les plus simples, cette structure de liste est directement interprétée pour exécuter le programme ; une fonction est littéralement un élément de cette structure de liste parcouru par l'interpréteur lors de son exécution. Cependant, la plupart des systèmes Lisp plus complets intègrent également un compilateur. Ce dernier traduit la structure de liste en code machine ou en bytecode pour son exécution. Ce code peut s'exécuter aussi rapidement que du code compilé dans des langages conventionnels tels que le C.
Les macros s'exécutent avant la compilation, offrant ainsi des possibilités intéressantes. Si un programme a besoin d'une table précalculée, une macro peut la créer à la compilation ; le compilateur n'a alors qu'à générer la table sans avoir à exécuter de code pour la créer. Certaines implémentations Lisp disposent même d'un mécanisme eval-whenpermettant d'inclure du code à la compilation (lorsqu'une macro en a besoin), mais pas dans le module généré.
Évaluation et boucle lecture-évaluation-impression
Les langages Lisp sont souvent utilisés avec une ligne de commande interactive , qui peut être associée à un environnement de développement intégré (IDE). L'utilisateur saisit des expressions dans la ligne de commande ou demande à l'IDE de les transmettre au système Lisp. Lisp lit les expressions saisies, les évalue et affiche le résultat. C'est pourquoi la ligne de commande Lisp est appelée boucle de lecture-évaluation-affichage ( REPL ).
Le fonctionnement de base du REPL est le suivant. Il s'agit d'une description simplifiée qui omet de nombreux éléments d'un Lisp réel, tels que les guillemets et les macros.
Cette sera lu comme la chaîne de caractères « 123 ».
La immédiate . En Common Lisp , les arguments sont évalués dans l'ordre applicatif (« du plus à gauche au plus interne »), tandis qu'en Scheme, l'ordre des arguments est indéfini, ce qui permet une optimisation par le compilateur.
structures de contrôle
À l'origine, Lisp comportait très peu de structures de contrôle, mais de nombreuses autres ont été ajoutées au cours de son évolution. (L'opérateur conditionnel originel de Lisp, ` la récursivité terminale . La popularité de Scheme dans l'enseignement de l'informatique a conduit certains étudiants à croire que la récursivité terminale est la seule, ou la plus courante, manière d'écrire des itérations en Lisp, ce qui est inexact. Tous les dialectes Lisp fréquemment rencontrés possèdent des constructions d'itération de style impératif, de la Common Lispappels terminaux . Ainsi, l'utilisation de la récursivité terminale est généralement encouragée en Scheme car cette pratique est explicitement prise en charge par la définition du langage. En revanche, Common Lisp (ANSI) n'impose pas l'optimisation communément appelée élimination des appels terminaux. Ainsi, le fait que le style récursif terminal comme remplacement occasionnel de l'utilisation de constructions d'itération plus traditionnelles (telles que saut ) et de correction du programme (puisque la récursivité terminale peut augmenter l'utilisation de la pile dans Common Lisp, risquant un dépassement de pile ).
Certaines structures de contrôle Lisp sont des opérateurs spéciaux , équivalents aux mots-clés syntaxiques d'autres langages. Les expressions utilisant ces opérateurs ont la même apparence que les appels de fonction, mais diffèrent en ce que les arguments ne sont pas nécessairement évalués — ou, dans le cas d'une expression d'itération, peuvent être évalués plusieurs fois.
Contrairement à la plupart des autres langages de programmation majeurs, Lisp permet d'implémenter des structures de contrôle directement dans le langage. Plusieurs de ces structures sont implémentées sous forme de macros Lisp et peuvent même être étendues par le programmeur souhaitant comprendre leur fonctionnement.
Common Lisp et Scheme possèdent tous deux des opérateurs pour le contrôle de flux non local. Les différences entre ces opérateurs constituent l'une des principales divergences entre les deux dialectes. Scheme prend en charge les continuations réentrantes grâce à la Haskell .
Grâce à son héritage en matière de traitement de listes, Lisp possède un large éventail de fonctions d'ordre supérieur permettant de parcourir des séquences. Dans de nombreux cas où une boucle explicite serait nécessaire dans d'autres langages (comme une Bonjour, monde ! » :
)
La syntaxe Lisp se prête naturellement à la récursivité. Les problèmes mathématiques, tels que l'énumération d'ensembles définis récursivement, sont simples à exprimer dans cette notation. Par exemple, pour calculer la factorielle d'un nombre :
la récursivité terminale :
Common Lispsystème d'objets Common Lisp (CLOS) fait partie intégrante d'ANSI Common Lisp. CLOS est issu de New Flavors et de CommonLOOPS. ANSI Common Lisp a été le premier langage de programmation orienté objet normalisé (1994, ANSI X3J13).
Flavors , développé au MIT , et son descendant New Flavors (développé par Symbolics ).
KR (abréviation de Knowledge Representation), un système d'objets basé sur des contraintes développé pour faciliter l'écriture de Garnet, une bibliothèque GUI pour Common Lisp .
Plusieurs systèmes d'exploitation , y compris les systèmes basés sur un langage , sont basés sur Lisp (utilisent des fonctionnalités, des conventions, des méthodes, des structures de données, etc. de Lisp), ou sont écrits en Lisp, notamment :
Genera, renamed Open Genera, by Symbolics; Medley, written in Interlisp, originally a family of graphical operating systems that ran on Xerox's later Starworkstations; Mezzano; Interim; ChrysaLisp, by developers of Tao Systems' TAOS; and also the Guix System for GNU/Linux.