Scheme est un dialecte minimaliste du langage de programmation Lisp, conçu pour faciliter un style de programmation fonctionnelle tout en promouvant une syntaxe simple et claire. Il se caractérise par son utilisation de parenthèses, un système de macros puissant, et une forte emphase sur la récursion et les procédures de première classe. Le langage encourage un paradigme de programmation fonctionnelle et prend en charge plusieurs techniques de programmation, y compris la programmation fonctionnelle, impérative et logique.
Scheme a été créé dans les années 1970 par Gerald Jay Sussman et Guy L. Steele Jr. au Massachusetts Institute of Technology (MIT). Il a été développé dans le but de simplifier et d'améliorer le langage Lisp original, qui était devenu complexe au fil du temps. La motivation derrière Scheme était de créer un langage qui serait plus facile à mettre en œuvre et à enseigner, tout en étant suffisamment puissant pour exprimer des idées complexes.
Au fil des ans, Scheme a subi diverses révisions et efforts de normalisation. Les normes les plus notables sont les RnRS (Revisedn Reports on the Algorithmic Language Scheme), qui ont formalisé le langage et ses caractéristiques. La communauté Scheme a depuis continué à développer le langage, menant à de nouvelles normes comme R6RS et R7RS, qui ont introduit de nouvelles fonctionnalités et améliorations.
À l'heure actuelle, Scheme reste populaire dans les environnements académiques, en particulier dans l'enseignement de l'informatique, en raison de son élégance et de sa syntaxe claire. Son influence peut être observée dans de nombreux langages de programmation modernes et paradigmes. Scheme est souvent associé à la communauté de la programmation fonctionnelle et a inspiré des langages tels que Clojure et Racket, qui se sont basés sur ses principes et ont étendu ses capacités.
Scheme utilise une syntaxe entièrement parenthétique où le code est écrit en notation préfixe ; par exemple, une opération d'addition est écrite comme (+ 1 2)
.
Les fonctions dans Scheme sont des citoyens de première classe, ce qui signifie qu'elles peuvent être passées comme arguments ou retournées par d'autres fonctions. Exemple :
(define (make-adder x)
(lambda (y) (+ x y)))
(define add5 (make-adder 5))
(add5 10) ; retourne 15
Scheme prend en charge l'optimisation des appels en queue, permettant aux fonctions de réutiliser le cadre de pile actuel pour les appels récursifs qui se produisent en position de queue, empêchant ainsi le débordement de pile.
Scheme permet l'utilisation de continuations, permettant aux programmeurs de capturer l'état actuel de la computation et de manipuler le flux de contrôle :
(call-with-current-continuation
(lambda (exit)
(exit 'done)))
Scheme dispose d'un puissant système de macros qui permet aux programmeurs de créer des extensions syntaxiques. Une macro simple peut être définie comme suit :
(define-syntax my-if
(syntax-rules ()
((_ test then else)
(if test then else))))
Scheme prend en charge l'abstraction des données à travers des structures comme les listes, les paires et les fonctions d'ordre supérieur, permettant une manipulation efficace des données.
Scheme utilise la portée lexicale, où la portée d'une variable est déterminée par sa position physique dans le code source. Cela conduit à un comportement prévisible concernant les liaisons de variables.
Scheme est dynamiquement typé, permettant aux variables de contenir des valeurs de n'importe quel type sans avoir besoin de déclarations de type explicites.
En tant que dialecte de Lisp, Scheme est optimisé pour le traitement des listes, facilitant l'exécution d'opérations sur les listes :
(define my-list (list 1 2 3 4))
(car my-list) ; retourne 1
(cdr my-list) ; retourne (2 3 4)
Les fonctions Scheme peuvent être définies récursivement avec une position de queue pour optimiser l'utilisation de la mémoire et les performances. Par exemple :
(define (factorial n)
(define (fact-helper n acc)
(if (zero? n)
acc
(fact-helper (- n 1) (* n acc))))
(fact-helper n 1))
Les applications Scheme peuvent généralement être construites en utilisant l'environnement d'exécution de l'implémentation choisie. Par exemple, dans Racket, vous pouvez utiliser l'outil en ligne de commande racket
pour exécuter des fichiers .rkt
ou les compiler en exécutables.
Plusieurs compilateurs et interpréteurs sont disponibles pour Scheme, y compris :
Scheme est largement utilisé dans le milieu académique pour enseigner les principes de programmation et comme outil de recherche en informatique. Il a des applications dans l'intelligence artificielle, la conception de langages et le scripting, ainsi que dans divers domaines nécessitant une computation symbolique ou une manipulation complexe de données.
Les deux langages supportent un style de programmation fonctionnelle, mais Python met l'accent sur la lisibilité et la simplicité, tandis que Scheme se concentre sur des expressions puissantes et concises. La syntaxe riche en parenthèses de Scheme peut être perçue comme un obstacle pour les débutants, tandis que la syntaxe basée sur l'indentation de Python est généralement plus accessible.
JavaScript prend également en charge la programmation fonctionnelle et possède des fonctions de première classe. Cependant, JavaScript a un système d'objet basé sur les prototypes, tandis que Scheme s'appuie sur des paradigmes fonctionnels. Le système de macros de Scheme offre des capacités non présentes dans JavaScript.
C est un langage de bas niveau, statiquement typé, conçu pour la programmation système, tandis que Scheme est de haut niveau et dynamiquement typé. C se concentre sur la performance et la manipulation au niveau matériel, tandis que Scheme met l'accent sur l'abstraction et les aspects théoriques de la computation.
Les deux langages sont enracinés dans la programmation fonctionnelle. Haskell utilise un système de types plus rigide et prend en charge l'évaluation paresseuse, tandis que le typage dynamique et l'évaluation avide de Scheme permettent une programmation plus flexible au prix de certaines performances.
Ruby est un langage de programmation orienté objet qui mélange des fonctionnalités de programmation fonctionnelle, tandis que Scheme est purement fonctionnel. La syntaxe de Ruby est plus verbeuse, tandis que la simplicité de Scheme provient de son design minimaliste.
La traduction de code Scheme vers d'autres langages peut être facilitée par des outils qui comprennent à la fois la syntaxe Scheme et le langage cible. Certains outils utiles de traduction de code source-à-source incluent :
Chicken Scheme fournit un compilateur qui peut traduire le code Scheme en C, rendant possible l'utilisation de bibliothèques C et la création d'exécutables efficaces.
Racket, un dérivé de Scheme, a des capacités intégrées pour transformer et compiler du code en JavaScript, facilitant le déploiement d'applications web.
Gambit Scheme peut compiler le code Scheme en C et en exécutables natifs, offrant des options de traduction efficaces pour des applications critiques en termes de performance.