Les questions vagues «Scheme vs Common Lisp» ne manquent pas à la fois sur StackOverflow et sur ce site. Je souhaite donc que celui-ci soit plus ciblé. La question s'adresse aux personnes qui ont codé dans les deux langues:
Lors du codage dans Scheme, quels éléments spécifiques de votre expérience de codage Common Lisp avez-vous le plus oublié? Ou, inversement, en codant en Common Lisp, qu'avez-vous oublié de coder en Scheme?
Je ne parle pas nécessairement uniquement de fonctionnalités linguistiques. Ce qui suit sont toutes des choses valables à manquer, en ce qui concerne la question:
- Bibliothèques spécifiques.
- Caractéristiques spécifiques des environnements de développement tels que SLIME, DrRacket, etc.
- Fonctions d'implémentations particulières, telles que la capacité de Gambit à écrire des blocs de code C directement dans votre source Scheme.
- Et bien sûr, les fonctionnalités linguistiques.
Exemples du type de réponses que j'espère:
- "J'essayais d'implémenter X dans Common Lisp, et si j'avais les suites de première classe de Scheme, j'aurais totalement fait Y, mais je devais plutôt faire Z, ce qui était plus pénible."
- "La création de scripts pour le processus de construction de mon projet Scheme devenait de plus en plus pénible à mesure que mon arbre source grandissait et que je reliais de plus en plus de bibliothèques C. Pour mon prochain projet, je suis revenu à Common Lisp."
- "J'ai une grande base de code C ++ existante, et pour moi, pouvoir intégrer des appels C ++ directement dans mon code Gambit Scheme valait totalement les défauts que Scheme peut avoir par rapport à Common Lisp, même en l'absence de prise en charge de SWIG."
J'espère donc des récits de guerre plutôt que des sentiments généraux tels que "Le régime est un langage plus simple", etc.
Réponses:
Mon diplôme de premier cycle était en sciences cognitives et intelligence artificielle. A partir de là, j'ai eu une introduction à Lisp à un cours. Je pensais que le langage était intéressant (comme dans "élégant") mais je n'y ai pas vraiment réfléchi avant de tomber sur la Dixième Règle de Greenspun beaucoup plus tard:
L'argument de Greenspun était (en partie) que de nombreux programmes complexes ont des interprètes intégrés. Plutôt que de construire un interprète dans un langage, il a suggéré qu'il serait plus logique d'utiliser un langage comme Lisp qui possède déjà un interpréteur (ou un compilateur) intégré.
À l'époque, je travaillais sur une application assez grosse qui effectuait des calculs définis par l'utilisateur à l'aide d'un interpréteur personnalisé pour une langue personnalisée. J'ai décidé d'essayer de réécrire son noyau dans Lisp sous la forme d'une expérience à grande échelle.
Cela a pris environ six semaines. Le code original était d'environ 100 000 lignes de Delphi (une variante de Pascal). En Lisp, cela a été réduit à environ 10 000 lignes. Encore plus surprenant, le moteur Lisp était 3-6 fois plus rapide. Et gardez à l’esprit que c’était le travail d’un néophyte Lisp! Toute cette expérience m'a vraiment ouvert les yeux. pour la première fois, j'ai vu la possibilité de combiner performance et expressivité dans une seule langue.
Quelque temps plus tard, lorsque j'ai commencé à travailler sur un projet Web, j'ai auditionné un certain nombre de langues. J'ai inclus Lisp et Scheme dans le mix. En fin de compte, j'ai sélectionné un schéma d'implémentation - Chez Scheme . Je suis très content des résultats.
Le projet Web est un "moteur de sélection" hautes performances . Nous utilisons Scheme de différentes manières, du traitement des données à leur interrogation en passant par la génération de pages. Dans de nombreux endroits, nous avons commencé avec une langue différente, puis avons migré vers Scheme pour des raisons que je vais décrire brièvement ci-dessous.
Maintenant, je peux répondre à votre question (au moins en partie).
Au cours de l'audition, nous avons examiné diverses applications de Lisp et Scheme. Du côté de Lisp, nous avons examiné (je crois) Allegro CL, CMUCL, SBCL et LispWorks. Du côté Scheme, nous avons examiné (je crois) Bigloo, Chicken, Chez, Gambit. (Le choix de la langue a été fait il y a longtemps; c'est pourquoi je suis un peu confus. Je peux extraire quelques notes si c'est important.)
Dès le départ, nous recherchions a) des threads natifs et b) un support Linux, Mac et Windows. Ces deux conditions combinées ont frappé tout le monde mais (je pense) Allegro et Chez out - donc, pour poursuivre l'évaluation, nous avons dû assouplir l'exigence du multi-threading.
Nous avons mis au point une série de petits programmes que nous avons utilisés pour l’évaluation et les tests. Cela a révélé un certain nombre de problèmes. Par exemple: certaines implémentations présentaient des défauts qui empêchaient certains tests de s’achever; certaines implémentations ne pouvaient pas compiler le code au moment de l'exécution; certaines implémentations ne pouvaient pas facilement intégrer du code compilé à l'exécution avec du code précompilé; certaines applications avaient des éboueurs nettement meilleurs (ou nettement pires) que les autres; etc.
Pour nos besoins, seules les trois implémentations commerciales - Allegro, Chez et Lispworks - ont réussi nos tests primaires. Des trois, seul Chez a réussi tous les tests avec brio. À l’époque, je pense que Lispworks n’avait pas de threads natifs sur aucune plate-forme (je pense qu’ils l’avaient maintenant) et je pense qu’Allegro n’avait que des threads natifs sur certaines plates-formes. De plus, Allegro avait des droits de licence d’exécution «appelez-nous» que je n’aimais pas beaucoup. Je crois que Lispworks n’avait aucuns frais d’exécution et Chez avait un arrangement simple (et très raisonnable) (et il ne s’engage que si vous avez utilisé le compilateur au moment de l’exécution).
Après avoir produit des morceaux de code assez significatifs dans Lisp et Scheme, voici quelques points de comparaison et de contraste:
Les environnements Lisp sont beaucoup plus matures. Vous en avez plus pour votre argent. (Ceci dit, plus de code équivaut aussi à plus de bugs.)
Les environnements Lisp sont beaucoup plus difficiles à apprendre. Vous avez besoin de beaucoup plus de temps pour devenir compétent; Common Lisp est un langage énorme - et c'est avant que vous ne trouviez les bibliothèques ajoutées aux implémentations commerciales. (Cela dit, le cas de la syntaxe de Scheme est bien plus subtil et compliqué que n'importe quoi en Lisp.)
Il est parfois un peu plus difficile de produire des fichiers binaires dans les environnements Lisp. Vous devez "secouer" votre image pour supprimer les bits inutiles. Si vous n'exercez pas votre programme correctement au cours de ce processus, des erreurs d'exécution risquent de se produire ultérieurement. . En revanche, avec Chez, nous compilons un fichier de niveau supérieur qui inclut tous les autres fichiers dont il a besoin et nous avons terminé.
J'ai déjà dit que nous avions utilisé Scheme dans un certain nombre d'endroits où nous n'avions pas l'intention initialement. Pourquoi? Je peux penser à trois raisons qui me viennent à l’esprit.
Premièrement, nous avons appris à faire confiance à Chez (et son développeur, Cadence). Nous avons beaucoup demandé à cet outil, qui a toujours été efficace. Par exemple, Chez a toujours eu un nombre de défauts trivial et son gestionnaire de mémoire a été très, très bon.
Deuxièmement, nous avons appris à aimer la performance de Chez. Nous utilisions quelque chose qui ressemblait à un langage de script - et nous en tirions une vitesse de code natif. Pour certaines choses qui importaient peu - mais ça ne faisait jamais mal, et parfois ça aidait énormément.
Troisièmement, nous avons appris à aimer l’abstraction que Scheme pouvait fournir. Je ne parle pas seulement de macros, au fait; Je parle de choses comme les fermetures, les lambdas, les coups de queue, etc. Une fois que vous commencez à penser en ces termes, les autres langues semblent plutôt limitées en comparaison.
Le régime est-il parfait? Non; c'est un compromis. Tout d’abord, cela permet aux développeurs individuels d’être plus efficaces - mais il est plus difficile pour les développeurs de s’enfiler dans le code de l’autre parce que les indicateurs utilisés par la plupart des langages (par exemple, les boucles for) sont manquants dans Scheme (par exemple, il existe un million de façons de le faire. une boucle for). Deuxièmement, il existe un groupe beaucoup plus restreint de développeurs à qui parler, engager, emprunter, etc.
En résumé, je dirais que Lisp et Scheme offrent des fonctionnalités qui ne sont pas disponibles partout ailleurs. Cette capacité est un compromis, elle aurait donc intérêt à être logique dans votre cas particulier. Dans notre cas, les facteurs déterminants entre le choix d'utiliser Lisp ou Scheme concernaient davantage des fonctionnalités très fondamentales (support de plate-forme, threads de plate-forme, compilation au moment de l'exécution, licences d'exécution) plutôt que des fonctionnalités de langage ou de bibliothèque. Encore une fois, dans notre cas, cela représentait également un compromis: avec Chez, nous avions les fonctionnalités essentielles que nous souhaitions, mais nous avions perdu les bibliothèques étendues des environnements Lisp commerciaux.
Aussi, juste pour répéter: nous avons examiné les différents Lisps et Schemes il y a longtemps; ils ont tous évolué et amélioré depuis.
la source
Habituellement, je n'aime pas coller un lien comme réponse, mais j'ai écrit un article sur ce blog. Ce n'est pas exhaustif, mais il passe en revue certains des principaux points.
http://symbo1ics.com/blog/?p=729
Edit : Voici les principaux points:
TERPRI
,PROGN
etc. Scheme a généralement des noms très judicieux. C'est quelque chose qui manque dans CL.list
" à "lst
" dans Scheme.syntax-rules
tout va bien jusqu'à ce que vous vouliez vraiment pirater certaines choses. D'autre part, les macros hygiéniques sont parfois omises dans CL. N'ayant aucun moyen standard de les faire, cela signifie réinventer la roue.Bien que je n’ai parlé qu’à la première personne un peu au-dessus, il devrait être clair ce qui me manque et ce qui ne me manque pas.
[Je m'excuse si elles sont trop générales. Il semble que vous souhaitiez beaucoup plus de détails spécifiques. Il y a quelques détails dans le post.]
la source
J'ai récemment démarré un projet personnel en utilisant une bibliothèque avec une version C et une version Java. Je voulais utiliser Lisp pour le projet et j'ai passé environ un mois entre Common Lisp, Scheme et Clojure. J'ai de l'expérience avec les trois projets, mais uniquement avec des projets de jouets. Je vais vous parler un peu de mon expérience avec chacun d’eux avant de vous dire laquelle j’ai finalement choisi.
PLT Racket a un bon IDE qui vous permet non seulement d’évaluer les expressions à partir de l’éditeur, mais également de taper des crochets au lieu de parenthèses, en les basculant à l’endroit approprié. Racket dispose également d’un grand nombre de bibliothèques avec l’installation et d’autres encore disponibles au téléchargement. Le débogueur visuel est également utile.
SMLL (Common Lisp implémentation) n’a pas d’EDI, mais il est habituel avec les implémentations CL à source ouverte d’utiliser Emacs et SLIME. Cette combinaison peut être très efficace. Outre la possibilité d'évaluer les expressions au fur et à mesure que vous les tapez dans le fichier source, il existe également un REPL qui contient toutes les commandes d'édition d'emacs, de sorte que la copie de code peut fonctionner efficacement dans les deux sens. Même les objets affichés dans le tampon REPL peuvent être copiés et collés.
Alt+(
etAlt+)
sont efficaces pour traiter les parenthèses et l'indentation appariées.Toutes les fonctionnalités d'Emacs ci-dessus sont également disponibles pour Clojure. Mon expérience de montage avec Clojure est similaire à celle de Lisp. L'interopérabilité Java a bien fonctionné et j'aimerais bien faire un projet Clojure une fois qu'il sera mûr.
J'ai pu accéder à la bibliothèque en utilisant les trois (Common Lisp, Racket et Clojure), mais j'ai finalement choisi Common Lisp pour le projet. Le facteur décisif était que le FFI était beaucoup plus facile à utiliser dans Common Lisp. Le CFFI a un très bon manuel avec un exemple de code et des explications détaillées sur chaque méthode. J'ai été en mesure d'envelopper 20 fonctions C dans un après-midi et je n'ai pas eu à toucher au code depuis.
L'autre facteur était que je connaissais mieux Common Lisp que Clojure ou R6RS Scheme. J'ai lu la plupart des livres de Practical Common Lisp et Graham et je suis à l'aise avec Hyperspec. Ce n'est pas encore très codé, mais je suis sûr que cela va changer à mesure que je gagne en expérience.
la source
Je programme en CL et en raquette.
Je développe actuellement un site Web dans Common Lisp et j'ai écrit une série de programmes internes pour mon ancien employeur de Racket.
Pour le code interne, j'ai choisi Racket (à l'époque appelé PLT Scheme) car l'employeur était un magasin Windows et je ne pouvais pas le faire payer pour LispWorks. La seule bonne implémentation CL open-source pour Windows était (et est toujours) CCL, ce qui nécessite la prise en charge de SSE par le processeur. L'employeur, étant bon marché, utilisait du matériel de l'âge de pierre. Même si l'employeur disposait d'un matériel de qualité, la seule bibliothèque d'interface graphique importante de Common Lisp est McCLIM, qui ne fonctionne que sous Unix. Racket possède une bonne bibliothèque d’interface graphique qui fonctionne à la fois sous Unix et Windows, ce qui était essentiel au succès de mon projet.
J'ai passé plus d'un an à supporter l'éditeur primitif DrRacket. EMACS n'a pas pu transformer la version graphique de Racket, connue à l'époque sous le nom de MrEd, en inferior-lisp sous Windows. Je devais faire sans pouvoir évaluer l'expression au niveau du curseur avec une seule frappe. Au lieu de cela, je devais sélectionner manuellement l'expression S, la copier, cliquer sur la fenêtre REPL (car il n'y avait aucune frappe sur laquelle basculer), puis coller l'expression S. Je devais aussi me passer d'un éditeur capable de me montrer les arguments attendus de la fonction ou de la macro que j'utilisais. DrRacket ne remplace pas SLIME.
L'employeur utilisait une base de données propriétaire avec une API XML complexe qui nécessitait des charges d'informations apparemment inutiles pour pouvoir répondre à sa version d'une requête SELECT. J'ai décidé d'utiliser HTMLPrag à la fois pour émettre du XML vers cette API et pour analyser les réponses. Cela a très bien fonctionné.
J'ai dû apprendre le système de macros "casse de syntaxe" surchargé de Racket afin d'écrire une macro qui me permettrait d'interagir avec l'API XML très compliquée en tapant des formulaires ressemblant à SQL. Cette partie aurait été beaucoup plus facile si j'avais DEFMACRO à ma disposition. Cependant, le résultat final était toujours sans faille même s'il a fallu déployer davantage d'efforts.
De plus, je devais me passer de la macro LOOP de Common Lisp. Racket a commencé à fournir une alternative seulement après que j'ai écrit la plupart du code, et l'alternative est toujours nul par rapport à LOOP (même si l'équipe de développement de Racket insiste sur le fait que c'est mieux - ils se trompent tout simplement). J'ai fini par écrire beaucoup de formulaires LET nommés qui utilisaient "car" et "cdr" pour parcourir les listes.
En parlant de voiture et cdr, rien n’est plus frustrant que l’interprétation de (voiture '()) de Scheme comme étant une erreur. J'ai profité de la sensibilité à la casse de Racket pour implémenter CAR et CDR, qui ont la sémantique de Common Lisp. Cependant, la séparation de '() et #f rend beaucoup moins utile de renvoyer' () comme valeur par défaut.
J'ai également fini par ré-implémenter UNWIND-PROTECT et j'ai inventé mon propre système de redémarrage pour combler le vide laissé par Racket. La communauté Racket doit savoir que les redémarrages sont très utiles et faciles à mettre en œuvre.
La forme let-values de Racket était trop verbeuse, j'ai donc implémenté MULTIPLE-VALUE-BIND. Cela était absolument nécessaire, car Racket exige que vous receviez toutes les valeurs générées, que vous les utilisiez ou non.
Plus tard, j’ai tenté d’écrire un client API XML eBay dans Common Lisp, mais j’ai constaté qu’il n’avait rien de tel que HTMLPrag. HTMLPrag est utile. J'ai fini par faire ce projet dans Racket. J’ai expérimenté les fonctionnalités de programmation alphabète de Racket, pour découvrir que je suis le seul programmeur sur Terre à trouver le code littéral écrit correctement plus difficile à modifier que le code ordinaire ou le code alphabétique "commentaires excessifs" mal écrit.
Mon nouveau projet est réalisé à Common Lisp, ce qui était le bon choix car la communauté Racket ne croit tout simplement pas au parallélisme, ce qui est essentiel pour ce projet. La seule chose que je pensais avoir peut-être manqué de Racket, ce sont les poursuites. Cependant, j'ai pu faire ce dont j'avais besoin en utilisant des redémarrages et, rétrospectivement, j'aurais probablement pu le faire avec une simple fermeture.
la source
cond
formulaire, par exemple) et des bugs (est-ce que j'ai écrit le test de terminaison de boucle correctement à cette époque?) Même aujourd'hui, j'ai l'impression Cette raquette est principalement destinée aux étudiants et non aux programmeurs professionnels. Chaque fois que j'entends parler de quelqu'un d'autre que moi qui l'utilise, ils utilisent la sous-langue "Étudiant débutant" et c'est pour une classe.Scheme est conçu avec une compilation séparée à l'esprit. En conséquence, la puissance de ses macros est souvent limitée de manière sévère, même avec les extensions qui permettent un defmacro de type Common Lisp au lieu d’un système de macro médiocre, limitant l’hygiène. Il n'est pas toujours possible de définir une macro définissant une autre macro destinée à une utilisation immédiate dans une ligne de code suivante. Et une telle possibilité est essentielle pour la mise en œuvre de compilateurs eDSL efficaces.
Il va sans dire que les implémentations Scheme avec uniquement des macros hygiéniques R5RS me sont à peine utiles, car mon style de métaprogrammation ne peut être traduit de manière adéquate en hygiène.
Heureusement, certaines implémentations de Scheme (par exemple, Racket) ne sont pas soumises à cette limitation.
la source