web-dev-qa-db-fra.com

Combien de primitives faut-il pour construire une machine LISP? Dix, sept ou cinq?

Sur ce site, ils disent qu'il y a 10 primitives LISP. Les primitives sont: atom, quote, eq, car, cdr, cons, cond, lambda, label, apply.

http://hyperpolyglot.wikidot.com/LISP#ten-primitives

Stevey estime qu'il y en a sept (ou cinq):

Cela fait partie de la pureté de l'idée de LISP: vous n'avez besoin que des sept (ou cinq?) Primitives pour construire la machine complète. http://steve-yegge.blogspot.com/2006/04/LISP-is-not-acceptable-LISP.html

Quel est le nombre minimum de primitives pour construire une machine LISP (c'est-à-dire quelque chose qui peut exécuter une fonction eval/value sur le code LISP)? (Et lesquels sont-ils?)

(Je peux comprendre que vous pourriez vivre sans atom, label and apply)

77
hawkeye

Voir cette autre question pour construire des macros à partir de l'ensemble de 7 primitives de Paul Graham.

8
DomQ

Prédicats de base/fonctions F

McCarthy Les fonctions S élémentaires et les prédicats étaient:

  1. atom

    Ce qui était nécessaire car car et cdr sont définis pour les listes uniquement, ce qui signifie que vous ne pouvez pas compter sur une sorte de réponse pour indiquer ce qui se passait si vous donniez un atome à car.

  2. eq

    Pour tester l'égalité entre les atomes.

  3. car

    Pour renvoyer la première moitié (adresse) de la cellule de contre. (Contenu du registre d'adresses).

  4. cdr

    Pour renvoyer la seconde moitié (décrément) de la contre-cellule. (Contenu du registre de décrémentation).

  5. cons

    Pour faire une nouvelle cellule contre, avec la moitié d'adresse contenant le premier argument à contre, et la moitié décrémentée contenant le deuxième argument.

Lier ensemble: fonctions S

Il a ensuite ajouté à sa notation de base, pour permettre l'écriture de ce qu'il a appelé les fonctions S:

  1. quote

    Représenter une expression sans l'évaluer.

  2. cond

    Conditionnel de base à utiliser avec les prédicats décrits précédemment.

  3. lambda

    Pour désigner une fonction.

  4. label

    Bien qu'il n'en ait pas eu besoin pour la récursivité, il ne connaissait peut-être pas le Y-Combinator ( selon Paul Graham ), il l'a ajouté pour plus de commodité et pour permettre récursivité.


Vous pouvez donc voir qu'il a en fait défini 9 "opérateurs" de base pour sa machine LISP. Dans une réponse précédente à une autre de vos questions, j'ai expliqué comment vous pouviez représenter et utiliser des nombres avec ce système.

Mais la réponse à cette question dépend vraiment de ce que vous voulez de votre machine LISP. Vous pouvez en implémenter une sans la fonction label, car vous pouvez simplement tout composer fonctionnellement et obtenir une récursivité en appliquant le Y-Combinator.

atom peut être ignoré si vous définissez l'opération car sur les atomes pour renvoyer NIL.

Vous pouvez essentiellement avoir la machine LISP de McCarthy avec 7 de ces 9 primitives définies, mais vous pouvez définir ostensiblement une version plus concise en fonction des inconvénients que vous souhaitez vous infliger. J'aime bien sa machine, ou les nombreuses primitives dans les langages plus récents comme Clojure.

58
Isaac

La meilleure façon de le savoir avec certitude est de l'implémenter. J'ai utilisé 3 étés pour créer Zozotez qui est un LISP McCarty-ish fonctionnant sur Brainfuck .

J'ai essayé de trouver ce dont j'avais besoin et sur un forum, vous trouverez un fil qui dit Vous n'avez besoin que de lambda. Ainsi, vous pouvez faire un LISP entier en calcul lambda que vous souhaitez. Je l'ai trouvé intéressant, mais ce n'est pas la voie à suivre si vous voulez quelque chose qui finit par avoir des effets secondaires et qui fonctionne dans le monde réel.

Pour un LISP complet de Turing, j'ai utilisé explication de Paul Graham sur l'article de McCarthy et tout ce dont vous avez vraiment besoin est:

  • évaluation des symboles
  • citation de formulaire spécial
  • formulaire spécial si (ou cond)
  • forme spéciale lambda (similaire à la citation)
  • fonction eq
  • atome de fonction
  • fonction contre
  • voiture de fonction
  • fonction cdr
  • fonction-répartition (liste-lambda)

C'est 10. En plus de cela, pour avoir une implémentation que vous pouvez tester et pas seulement sur une planche à dessin:

  • fonction lue
  • écriture de fonction

C'est 12. Dans mon Zozotez j'ai implémenté aussi set et flambda (macro anonyme, comme lambda). Je pourrais lui alimenter une bibliothèque implémentant n'importe quel LISP lié dynamiquement (Elisp, picoLisp) à l'exception des E/S de fichiers (car le BF sous-jacent ne le prend pas en charge autre que stdin/stdout).

Je recommande à quiconque d'implémenter un interpréteur LISP1 dans LISP et (pas LISP) pour bien comprendre comment un langage est implémenté. LISP a une syntaxe très simple, c'est donc un bon point de départ pour un analyseur. Je travaille actuellement sur un compilateur de schémas écrit en schémas avec différentes cibles (comme Staline est pour la cible C), j'espère que BF est l'un d'entre eux.

14
Sylwester

McCarthy a utilisé sept opérateurs pour définir le LISP d'origine: quote, atom, eq, car, cdr, cons et cond. Cet article retrace ses pas.

10
Vijay Mathew

This faq déclare:

Il n'y a pas un seul "meilleur" ensemble minimal de primitives; tout dépend de la mise en œuvre. Par exemple, même quelque chose d'aussi basique que les nombres n'a pas besoin d'être primitif et peut être représenté sous forme de listes. Un ensemble possible de primitives pourrait inclure CAR, CDR et CONS pour la manipulation des expressions S, READ et PRINT pour l'entrée/sortie des expressions S et APPLY et EVAL pour les tripes d'un interprète. Mais vous voudrez peut-être ajouter LAMBDA pour les fonctions, EQ pour l'égalité, COND pour les conditions, SET pour l'affectation et DEFUN pour les définitions. DEVIS pourrait également être utile.

Cela vient du site Web de la School of Computer Science, Carnegie Melon.

8
bennybdbc

Paul Graham implémente eval en utilisant sept .

Dans le Micro Manual de McCarthy pour LISP, il implémente eval en utilisant ten .

2
hawkeye

Vous vous avez juste besoin d'une instruction x86 MOV .

"Le M/o/Vfuscator (" o "court, sonne comme" mobfuscator ") compile les programmes en instructions" mov ", et uniquement les instructions" mov ". Arithmétique, comparaisons, sauts, appels de fonction et tout ce dont un programme a besoin est toutes effectuées par des opérations mov; il n'y a pas de code auto-modifiable, pas de calcul déclenché par le transport, et aucune autre forme de triche non-mov. "

Sérieusement, ces primitives n'implémenteront pas de machine LISP. Une machine a besoin d'installations comme les E/S et la collecte des ordures. Sans parler d'un mécanisme d'appel de fonction! D'accord, vous avez sept primitives qui sont des fonctions. Comment la machine appelle-t-elle une fonction?

La bonne compréhension de ce que ces primitives rendent possible est qu'elles exposent le jeu d'instructions d'une machine de Turing universelle . Parce que ces instructions sont "Lispy", par un glissement de la langue (parler avec un LISP), nous appelons sournois cela une "Machine LISP". "Universel" signifie que la machine est programmable: avec quelques instructions de combinaison appliquées à la machine de Turing universelle, nous pouvons instancier n'importe quelle machine de Turing. Mais jusqu'à présent, tout cela est purement une construction mathématique.

Pour simuler réellement cet UTM - le réaliser physiquement afin de l'explorer sur un ordinateur, nous avons besoin d'une machine qui nous fournit un moyen de saisir réellement les formulaires qui créent des machines de Turing à partir de combinaisons de ces sept instructions LISP. Et nous avons également besoin d'une forme de sortie; la machine pour au moins être en mesure de nous dire "oui", "non" ou "Attendez, je suis toujours en marche".

En d'autres termes, la seule façon dont ces sept instructions peuvent fonctionner est qu'elles soient hébergées sur une machine plus grande qui fournit l'environnement.

Notez également que les sept primitives de Graham ne prennent pas explicitement en charge les nombres, vous devrez donc les construire à partir de fonctions (technique des "chiffres de l'Église"). Aucune implémentation LISP de production ne fait une chose aussi folle.

1
Kaz