Lisp是如何动态和编译的?

Lisp是如何动态和编译的?,lisp,common-lisp,Lisp,Common Lisp,我不明白Lisp是如何编译和动态的。对于一种能够操作、修改和生成代码的语言来说,这不是一种需要解释的要求吗?一种语言是否可能被完全编译并且仍然是动态的?还是我遗漏了什么?Lisp在做什么,使它既可以编译又可以动态 对于一种能够操作、修改和生成代码的语言来说,这不是一种需要解释的要求吗 没有 一种语言是否可能被完全编译并且仍然是动态的 对 还是我遗漏了什么 对 Lisp在做什么,使它既可以编译又可以动态 它是动态编译的,就像大多数java和PyPy的实现一样。Lisp是一个广泛的语言和实现家族 L

我不明白Lisp是如何编译和动态的。对于一种能够操作、修改和生成代码的语言来说,这不是一种需要解释的要求吗?一种语言是否可能被完全编译并且仍然是动态的?还是我遗漏了什么?Lisp在做什么,使它既可以编译又可以动态

对于一种能够操作、修改和生成代码的语言来说,这不是一种需要解释的要求吗

没有

一种语言是否可能被完全编译并且仍然是动态的

还是我遗漏了什么

Lisp在做什么,使它既可以编译又可以动态


它是动态编译的,就像大多数java和PyPy的实现一样。

Lisp是一个广泛的语言和实现家族

Lisp上下文中的动态意味着代码在运行时具有一定的灵活性。例如,它可以更改或替换。这与动态类型不同

用Lisp编译

通常Lisp实现在运行时有一个可用的编译器。当这个编译器是增量编译器时,它不需要整个程序,但可以编译单个Lisp表单。然后我们说编译器支持增量编译

请注意,大多数Lisp编译器不仅仅是实时编译器。作为程序员,您可以调用编译器,例如在CommonLisp中调用函数和。然后编译Lisp代码

此外,大多数同时带有编译器和解释器的Lisp系统允许解释代码和编译代码自由混合执行

在公共Lisp中,还可以指示编译器编译代码的动态程度。一个更高级的Lisp编译器,如的编译器(或许多其他编译器),可以生成不同的代码

示例

(defun foo (a)
  (bar a 3))
上面的函数
foo
调用函数
bar

如果我们有一个全局函数
bar
,并重新定义它,那么我们通常期望在Lisp中新函数
bar
将被
foo
调用。我们不必重新编译
foo

我们来看看。它编译为虚拟机的字节码。这不是本机代码,但出于我们的目的,它更容易阅读

CL-USER 1 > (defun foo (a)
              (bar a 3))
FOO

CL-USER 2 > (compile 'foo)

FOO
NIL
NIL

[3]> (disassemble #'foo)

Disassembly of function FOO
(CONST 0) = 3
(CONST 1) = BAR
1 required argument
0 optional arguments
No rest parameter
No keyword parameters
4 byte-code instructions:
0     (LOAD&PUSH 1)
1     (CONST&PUSH 0)                      ; 3
2     (CALL2 1)                           ; BAR
4     (SKIP&RET 2)
运行时查找

因此,您可以看到对
BAR
的调用执行运行时查找。它查看符号
,然后调用符号的函数。因此,符号表充当全局函数的注册表

此运行时查找与增量编译器(可在运行时使用)相结合,使我们能够生成Lisp代码,对其进行编译,将其加载到当前的Lisp系统中,并让其逐段修改Lisp程序

这是通过使用间接寻址来完成的。在运行时,Lisp系统查找名为
bar
的当前函数。但请注意,这与汇编或解释无关。如果编译器编译
foo
,并且生成的代码使用此机制,则它是动态的。因此,在解释代码和编译代码中都会有查找开销

自70年代以来,Lisp社区投入了大量精力使编译器和解释器的语义尽可能相似


像Common Lisp这样的语言还允许编译器降低编译代码的动态性。例如,在运行时不查找代码某些部分的函数。

它可以同时编译和动态,因为它是后期绑定的。您可以运行函数和参数列表,然后向其中添加一些内容,然后再次运行。基本上,代码的每个部分都可以运行,而不仅仅是整个函数。

不一定是JIT。Lisp代码可以在程序执行期间的任意点进行编译,而不必在执行时“及时”。SBCL会立即编译。我不确定这是否算作“即时”。@ThomasBartscher在生成fasl时立即编译为本机代码?我不知道,但我认为是这样的。不知道为什么它总是以REPL方式立即编译。@ThomasBartscher很公平。就像说,
tcc
是“动态的”一样。您只需要一个运行时可用的编译器。@SK logic和一个智能链接器和加载器。@WillNess,
tcc
不需要任何链接器,它可以将二进制代码直接发送到内存中。@SK logic太棒了!因此,TCC是一体式的。:)也许也想看看这个:这不是一个令人难以置信的长篇大论的说法吗,说Common Lisp是后期绑定的吗?@Marcin:现在更长篇大论了。