2014-01-10 39 views
1

Lisp是homoiconic,意味着代碼可以被視爲數據。哪些實現允許我在運行時執行此操作?以下是僞代碼示例:哪個lisp實現允許我在運行時修改代碼?

(defun (my-func) 
    (display "foo ") 
    (display "bar ") 
    (display "baz ")) 

(defun (main-loop) 
    (my-func) 
    (swap (first my-func) (second my-func)) 
    (main-loop)) 

應重複輸出「foo bar baz bar foo baz」。

+0

我不知道具體實施的 - 但看的人,當他們評價不編譯。因此,這將排除SBCL的實例(可能還有很多現代的Common Lisp實現)。 – verdammelt

+0

基本上是一個副本:http://stackoverflow.com/questions/16914779/levels-of-homoiconicity –

+1

@verdammelt:請參閱http://www.sbcl.org/manual/#Interpreter –

回答

2

這可能不是最優雅的做法,但Common Lisp中,你可以做這樣的事情:

> (setq f '(defun foo() (princ "foo ") (princ "bar ") (princ "baz "))) 
(DEFUN FOO NIL (PRINC "foo ") (PRINC "bar ") (PRINC "baz ")) 
> (eval f) 
FOO 
> (foo) 
foo bar baz 
NIL 
> (defun frot() 
     ; Call foo (stored in f) 
     (funcall (eval f)) 
     ; Swap the 1st and 2nd statements in foo 
     (setf tmp (cadddr f)) 
     (setf (cadddr f) (cadr (cdddr f))) 
     (setf (cadr (cdddr f)) tmp))) 
FROT 
> (frot) 
foo bar baz 
(PRINC "foo ") 
> (frot) 
bar foo baz 
(PRINC "bar ") 
> (frot) 
foo bar baz 
(PRINC "foo ") 

f存儲Lisp的函數,而不是在原地執行它,但它確實說明了一個事實,即Lisp程序本身就是一個Lisp數據結構,而不是可以動態操作和執行的。

+0

考慮到您實際上並沒有從'FOO'中抽取源代碼,而只是將源代碼存儲在'F'中並對其進行評估以定義函數 - 您是否可以在Common Lisp的任何實現中執行此操作? (另外,請注意,在你的'frot' defun表單末尾有一個不匹配的括號。) – svk

+0

@svk我會這麼認爲,因爲它是相當香草的ANSI Lisp。但是,我只是驗證了它在Clisp和sbcl上的行爲。這兩種方法都有效,並且sbcl發出了關於賦予'f'的警告。 – lurker

2

其他答案涵蓋了這個問題。

但是,從實踐層面,如果你正在使用的Common Lisp和煤泥,並希望能夠編譯代碼到退出Emacs正在運行的程序,你需要告訴斯旺克從您的循環內進行更新。

將以下內容添加到您的代碼中,然後在循環中添加(更新swank)

(defmacro continuable (&body body) 
    `(restart-case 
     (progn ,@body) 
    (continue() :report "Just Continue"))) 

(defun update-swank() 
    "Called from within the main loop, this keep the lisp repl working" 
    (continuable 
    (let ((connection (or swank::*emacs-connection* 
         (swank::default-connection)))) 
     (when connection 
     (swank::handle-requests connection t))))) 

這是使用你可以用你的編輯器重新編譯直播as in this video(對不起,我堵自己的VID)事實的一種方式。

另一種方式(再次與斯萊姆)是告訴它使用不同的線程進行通信。但我更喜歡前一種方法,因爲在跨線程使用時,opengl非常不穩定。

[詳細信息] 上述代碼中的可持續宏捕獲任何錯誤,並讓您選擇忽略它並繼續。我發現這真的很有幫助,我經常在repl中犯錯誤,我不想從錯誤中「中止」,因爲這會中止我的主循環。

1

如果您按照描述修改代碼,那麼您知道代碼結構的一些內容。既然你知道代碼的結構,可以參數化該結構

(define (foo-er foo bar baz) 
    (lambda() 
    (display foo) 
    (display bar) 
    (display baz))) 

然後你就可以明確地傳遞你的論點就像做了交換:

(define (main-loop) 
    (let looping ((foo "foo ") (bar "bar ") (baz "baz ")) 
    ((foo-er foo bar baz)) 
    (looping bar foo baz))) 

> (main-loop) 
foo bar baz bar foo baz foo bar baz ... 

的CommonLisp版本是類似的。

如果你需要保持my-func各地:

(define my-funC#f) 
(define (main-loop) 
    (let looping ((foo "foo ") (bar "bar ") (baz "baz ")) 
    (set! my-func (foo-er foo bar baz) 
    (my-func) 
    (looping bar foo baz))) 
相關問題