2013-06-04 9 views
9

Dies ist eine Folge zu meinem previous question. Ich bin nicht überzeugt, dass Lisp-Code so homoikonisch ist wie Maschinencode auf einer Von-Neumann-Architektur. Es scheint mir offensichtlich, dass Code in beiden Fällen als Daten dargestellt wird, aber es scheint auch offensichtlich, dass Sie diese Eigenschaft im Maschinencode viel freier nutzen können als in Lisp.Ebenen der Homoiconicity

Wenn man mit Maschinencode herumfummelt, ist selbst modifizierender Code so einfach, dass er ständig passiert, oft durch Zufall und mit (meiner Erfahrung nach) urkomischen Ergebnissen. Beim Schreiben eines einfachen "print the numbers 0-15" -Programms könnte ich einen "off by one" -Fehler mit einem meiner Zeiger haben. Am Ende werde ich versehentlich alles, was in Register 1 ist, in die Adresse im Speicher ablegen, die die nächste Anweisung enthält, und stattdessen wird eine zufällige Anweisung ausgeführt. Gott weiß, wo es enden wird und was es tun wird, nachdem das passiert ist.

Es gibt wirklich keine Trennung zwischen Code und Daten. Alles ist gleichzeitig eine Anweisung (auch wenn es nur ein NOP ist), ein Zeiger und eine einfache alte Zahl. Und es ist möglich, dass sich der Code vor Ihren Augen ändert.

Bitte helfen Sie mir mit einem Lisp-Szenario Ich habe mich am Kopf kratzt. Sage ich das folgende Programm haben:

(defun factorial (n) 
    (if (<= n 1) 
     1 
     (* n (factorial (- n 1))))) 
; -- Demonstrate the output of factorial -- 
; -- The part that does the Self modifying goes here – 
; -- Demonstrate the changed output of factorial 

Nun, was ich passieren soll, ist zu diesem Programm einige Lisp-Code anhängen, die die * a + ändern, ändern Sie die < = auf eine> =, Stick a (+ 1 2 3) irgendwo da drin, und generell die Funktion kaputt machen. Und dann möchte ich, dass das Programm das absolute Durcheinander ausführt, das daraus resultiert.

Wichtiger Hinweis: Sofern ich nicht einige schwerwiegende Fehler im Beispielcode gemacht habe, dürfen Sie nur den -– More code goes here –- Teil ändern. Was Sie oben sehen ist der Code. Ich möchte nicht, dass du die ganze Liste zitierst und sie in einer Variablen ablegst, so dass sie manipuliert und als separate Funktion mit dem gleichen Namen ausgespuckt werden kann; Ich will keine Standarddefinition von Fakultät als etwas völlig anderes. Ich möchte genau diesen Code, den ich auf meinem Bildschirm sehen kann, um mich vor meinen Augen zu ändern, genau wie der Maschinencode.

Wenn dies eine unmögliche/unzumutbare Anfrage ist, dann verfestigt es nur weiter in meiner Vorstellung die Idee, dass Homoiconicity keine diskrete Eigenschaft ist, die eine Sprache entweder hat oder nicht, es ist ein Spektrum und Lisp ist nicht bei die blutende Kante. (Alternativ ist Lisp so homoikonisch, wie sie kommen, und ich suche nach einem anderen Begriff, der Maschinencode-ähnliche Selbstmodifizierung beschreibt)

+0

auch, inb4 kommentieren, dass der Code auf meinem Bildschirm ist unwahrscheinlich, vor meinen Augen zu ändern, weil es nur etwas Text auf einer Webseite ist. Wenn Sie ehrlich nicht verstehen, was ich meine und nicht trolling werde ich versuchen, etwas mehr zu klären :) – TheIronKnuckle

+0

Typische Maschinencode ist nicht "homoiconic", und Assemblersprache weniger. Obwohl Maschinencode ein Array von Bits ist, verfügen Maschinensprachen nicht über die Werkzeuge, um Arrays von Bits, die Maschinensprachenprogramme darstellen, spezifisch zu bearbeiten. Zum Beispiel wissen Sie bei einem Array von Bits nicht einmal, wo, sagen wir, der 17. Befehl beginnt, es sei denn, sie sind alle genau gleich lang. Wenn Sie Code in eine Vorlage einfügen, müssen Verzweigungs-Offsets, die den Einfügepunkt kreuzen, neu berechnet und gepatcht werden. Sie benötigen eine große Bibliothek von Routinen, um alles zu tun, und es ist nicht in der Maschinensprache enthalten. – Kaz

+0

Maschinensprachen ** haben tatsächlich die Werkzeuge, um Bitgruppen, die Maschinensprachenprogramme darstellen, spezifisch zu manipulieren. Jedes Mal, wenn Sie eine "Store" -Anweisung verwenden, ist genau das, was vor sich geht. – TheIronKnuckle

Antwort

15

Das ist einfach. Sie müssen nur die Listendarstellung ändern. Alles, was Sie brauchen, ist ein Lisp Interpreter.

Die Common Lisp Umsetzung LispWorks bietet uns ein Lisp-Interpreter:

CL-USER 137 > (defun factorial (n) 
       (if (<= n 1) 
        1 
        (* n (factorial (- n 1))))) 
FACTORIAL 

CL-USER 138 > (fifth (function-lambda-expression #'factorial)) 
(IF (<= N 1) 1 (* N (FACTORIAL (- N 1)))) 

CL-USER 139 > (fourth (fifth (function-lambda-expression #'factorial))) 
(* N (FACTORIAL (- N 1))) 

CL-USER 140 > (setf (first (fourth (fifth (function-lambda-expression 
              #'factorial)))) 
        '+) 
+ 

CL-USER 141 > (fourth (fifth (function-lambda-expression #'factorial))) 
(+ N (FACTORIAL (- N 1))) 

CL-USER 142 > (factorial 10) 
55 

CL-USER 143 > (setf (first (fourth (fifth (function-lambda-expression 
              #'factorial)))) 
        '*) 
* 

CL-USER 144 > (factorial 10) 
3628800 

Hier ist ein Beispiel, wo eine Funktion selbst modifiziert. Um es etwas einfacher zu machen, benutze ich eine Funktion von Common Lisp: Es erlaubt mir, Code zu schreiben, der nicht nur eine verschachtelte Liste ist, sondern ein Graph. In diesem Fall kann die Funktion seinen eigenen Code zugreifen:

CL-USER 180 > (defun factorial (n) 
       (if (<= n 1) 
        1 
        (progn 
        (setf (first '#1=(* n (factorial (- n 1)))) 
          (case (first '#1#) 
          (+ '*) 
          (* '+))) 
        #1#))) 
FACTORIAL 

Above-Funktion verwendet alternativ + oder * durch seinen Code zu modifizieren.

#1= ist ein Etikett im Ausdruck, #1# verweist dann auf dieses Etikett.

CL-USER 181 > (factorial 10) 
4555 

In früheren Zeiten (70er/80er Jahre) in einigen Lisp Gruppen die Entwickler wurden mit einem Texteditor nicht Lisp-Code zu schreiben, sondern ein Struktureditor. Die Editor-Befehle veränderten direkt die Struktur des Lisp-Codes.

+1

haha ​​wow. Das ist großartig. Ich habe so etwas für yonks gesucht. Und ich denke, es gibt nichts, was dich davon abhält, sowas auch außerhalb einer REPL zu machen (also könntest du möglicherweise eine rekursive Funktion haben, die sich immer wieder selbst verändert?) – TheIronKnuckle

+0

Bitte beachten Sie, dass dies nicht übertragbar ist Common Lisp, wie FUNCTION- LAMBDA-EXPRESSION darf NIL zurückgeben. –

+2

@ThomasBartscher: wahr. Ich nehme auch an, dass es ein Dolmetscher ist - auch etwas, das nicht tragbar ist. Bei Common Lisp geht es nicht nur um die portable Sprache, sondern auch darum, wo individuelle Implementierungen einen gewissen Freiheitsgrad haben (Interpreter vs. Compiler, Entwicklung vs. Lieferung, Optimierungen, Garbage Collection, ...). Wählen Sie einfach eine Common Lisp-Implementierung, die über die richtigen Funktionen verfügt. –