2014-01-10 40 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))) 
相关问题