为什么大多数S表达式语言是动态类型的?

25

为什么大多数的Lisp和Scheme语言都是动态类型的?静态类型与它们的一些常见特性不兼容吗?

3个回答

17

打字和s表达式可以结合使用,详见 Typed Scheme

部分原因是历史巧合,使得s表达式语言具有动态类型。这些语言往往更依赖于宏(macros),并且在处理 s 表达式时易于解析和模式匹配,从而使得宏处理更加容易。大部分关于复杂宏的研究都发生在s表达式语言中。

类型化的卫生宏 (Typed Hygienic Macros) 非常困难。


3
Typed Scheme不是静态类型语言,它提供类型作为错误检查。静态类型语言会拒绝编译,除非编译器可以证明程序完全是类型安全的。Typed Scheme仍然会产生运行时类型错误,而在静态类型语言中这是不可能的。 - Zorf
2
@Lajla,是的,虽然我没有说过类型化的 Scheme 是静态类型的。 - Doug Currie
6
Typed Racket是静态类型语言:类型检查发生在编译时。如果您无法通过Typed Racket类型检查器,则无法继续。在正常操作下,一旦类型检查通过,Typed Racket将应用优化(http://docs.racket-lang.org/ts-reference/Optimization_in_Typed_Racket.html),这些优化在没有来自类型检查的类型保证的情况下会不安全。 - dyoo
@Zorf 无稽之谈,当存在类型不匹配时,TR 将在编译时失败。 - Coderino Javarino

13

当Lisp在1958年到1960年间被发明时,它引入了许多特性作为语言和实现(垃圾回收、自举编译器等)。一些特性是从其他语言继承而来的(列表处理等),并进行了一些改进。该语言使用函数进行计算。S表达式更多地是一种实现细节(当时),而不是语言特性。类型系统不是语言的一部分。以交互方式使用该语言也是早期的实现特性。

在那个时候,功能性语言的有用类型系统尚未发明。即使到今天,在交互方式中使用静态类型语言仍然相对困难。虽然有许多静态类型语言的实现提供了一些交互式界面,但它们大多数不像典型的Lisp系统一样提供与交互使用相同级别的支持。使用交互式Lisp系统编程意味着许多东西可以随时更改,如果类型更改必须在整个程序和数据中传播,这可能会成为问题。要注意的是,一些Scheme程序员有不同的看法。R6RS通常是批处理语言,不太符合Lisp精神...

后来发明的具有静态类型系统的功能语言也采用了非S表达式语法-它们没有提供对宏或相关特性的支持。后来,这些语言/实现中的一些使用预处理器进行语法扩展。


2
有趣,你为什么说R6RS主要是批处理语言? - Luís Oliveira
5
R6RS没有描述语言的交互使用的语义学。例如EVAL是一个库函数,完全未经详细说明。实现可能会尝试解决这个问题,但似乎R6RS的作者也对交互使用不感兴趣。因此,没有任何关于库和REPL的内容。总的来说,除了所描述的语言技术限制外,我对R6RS标准的质量完全感到失望。我希望R7RS可以变得更好。 - Rainer Joswig

5

静态类型是词法的,这意味着可以从阅读源代码而不需要评估任何表达式或计算任何内容来推断出有关类型的所有信息,其中条件语句最为重要。 静态类型语言的设计是为了实现这一点,更好的术语应该是“词法类型化”,即编译器可以仅从源代码中证明不会发生任何类型错误。

在lisp的情况下,这种情况非常尴尬,因为lisp的源代码本身不是静态的,lisp是同构的,它使用数据作为代码,并且可以在某种程度上动态编辑自己运行的源代码。

Lisp是第一种动态类型语言,也可能因此,Lisp的程序代码本身不再是词法的。

编辑:在静态类型的情况下,您必须键入列表。 您可以为每个列表拥有极其复杂的类型,其中包含所有元素,或者要求每个元素具有相同的类型并将其类型为该类型的列表。 前者选项将在列表的列表中产生问题。 后一选项要求源代码仅包含每个数据的相同类型,这意味着您甚至无法构建表达式,因为列表与整数不同。

因此,我敢说这是完全不可行的。


2
这只是困难,而不是不可能的。请参考MetaML和MetaOCaml作为反例。依赖类型的语言也可以做到这一点-请参见Idris中关于部分求值的实验。 - Jacques Carette
1
必须移除很多内容,才能几乎不再谈论“基于S表达式”的问题。S表达式的一个核心思想是应用函数,它使代码本身具有动态性,因此静态地证明类型错误的不存在是不可能的。看看MetaML和MetaOCaml,我没有看到任何迹象表明它们是基于S表达式或同构图的。 - Zorf

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接