是否可以使用静态类型的完整Lisp变体?


107

是否可以使用静态类型的完整Lisp变体?存在这样的东西甚至有意义吗?我相信Lisp语言的优点之一就是其定义的简单性。静态类型会损害这一核心原则吗?


10
我喜欢Lisp的自由格式宏,但是我喜欢Haskell的类型系统的健壮性。我很想看看静态类型的Lisp是什么样子。
mcandre 2011年

4
好问题!我相信shenlanguage.org做到了。我希望它成为主流。
Hamish Grubijan


您如何使用Haskell进行符号计算?(解决'x'(=(+ xy)(* xy))))。如果将其放在字符串中,则不会进行检查(与Lisp不同,后者可以使用宏来添加检查)。如果您使用代数数据类型或列表...将会非常冗长:solve(Sym“ x”)(Eq(Plus(Sym“ x”)(Sym“ y”))(Mult(Sym“ x”) (Sym“ y”)))
aoeu256 '19

Answers:


57

是的,这是很有可能的,尽管对于大多数惯用的Lisp / Scheme代码而言,标准的HM样式类型系统通常是错误的选择。有关使用静态类型的“ Full Lisp”(实际上更类似于Scheme)的最新语言,请参见Typed Racket


1
这里的问题是,构成一个类型的球拍程序的整个源代码的列表的类型是什么?
佐夫

18
通常是这样Sexpr
Eli Barzilay

但是,我可以用coerce :: a->b评估的方式来写。类型安全在哪里?
ssice

2
@ssice:当您使用无类型的函数时,例如,eval您需要测试结果以查看结果,这在Typed Racked中没有什么新的(与采用String和类型的并集类型的函数相同Number)。可以做到这一点的一种隐含方式是,您可以用HM静态类型的语言编写和使用动态类型的语言。
Eli Barzilay

37

如果您想要的只是一种看起来像 Lisp 的静态类型的语言,则可以通过定义代表您的语言的抽象语法树,然后将该AST映射到S表达式来轻松实现。但是,我认为我不会将结果称为Lisp。

如果您希望除了语法之外还具有Lisp-y特性的东西,可以使用静态类型的语言来实现。但是,Lisp有许多特性很难获得很多有用的静态类型。为了说明这一点,让我们看一下称为cons的列表结构本身,它构成了Lisp的主要构建块。

将cons称为清单,虽然(1 2 3)看起来像一个清单,但有点用词不当。例如,它根本无法与静态类型列表(例如C ++ std::list或Haskell列表)相比。这些是一维链接列表,其中所有单元格均为同一类型。Lisp高兴地允许(1 "abc" #\d 'foo)。另外,即使您将静态类型的列表扩展为涵盖列表列表,这些对象的类型也要求列表中的每个元素都是一个子列表。您将如何代表((1 2) 3 4)他们?

Lisp cons形成二叉树,具有叶子(原子)和分支(cones)。此外,这种树的叶子可能根本不包含任何原子(非cons)Lisp类型!这种结构的灵活性使Lisp非常擅长处理符号计算,AST和Lisp代码本身的转换!

那么如何用静态类型的语言对这种结构进行建模呢?让我们在Haskell中尝试一下,它具有强大而精确的静态类型系统:

type Symbol = String
data Atom = ASymbol Symbol | AInt Int | AString String | Nil
data Cons = CCons Cons Cons 
            | CAtom Atom

您的第一个问题将是Atom类型的范围。显然,我们还没有选择一种足够灵活的Atom类型来涵盖我们想悬而未决的所有类型的对象。假设我们有一个神奇的类型类,而不是尝试扩展上面列出的Atom数据结构(您可以清楚地看到它很脆弱)。Atomic,区分了所有我们想要构成原子的类型。然后,我们可以尝试:

class Atomic a where ?????
data Atomic a => Cons a = CCons Cons Cons 
                          | CAtom a

但这是行不通的,因为它要求树中的所有原子都属于同一类型。我们希望它们能够因叶而异。更好的方法需要使用Haskell的存在量词

class Atomic a where ?????
data Cons = CCons Cons Cons 
            | forall a. Atomic a => CAtom a 

但是现在您到了问题的症结所在。您可以用这种结构的原子做什么?它们可以用Atomic a什么共同点建模?这样的类型可以保证什么类型的安全性?请注意,我们没有在类型类中添加任何函数,这是有充分理由的:原子在Lisp中没有任何共同点。它们在Lisp中的超类型简称为t(即top)。

为了使用它们,您必须想出一种机制来动态地将原子的值强制为您可以实际使用的值。至此,您基本上已经在静态类型语言中实现了一个动态类型子系统!(人们不禁会注意到Greenspun的《第十条编程规则》的一个可能推论。)

请注意,Haskell仅为这种具有类型的动态子系统提供支持,该子系统与类型和Typeable类Obj结合使用以替换我们的类,该类允许将任意值与其类型存储在一起,并从这些类型中显式强制返回。这就是您需要使用Lisp cons结构完全通用的系统。DynamicAtomic

您还可以执行另一种方法,将静态类型的子系统嵌入本质上为动态类型的语言中。这使您可以对程序的各个部分进行静态类型检查,从而可以利用更严格的类型要求。例如,这似乎是CMUCL的有限类型精确类型检查中采用的方法。

最后,可能存在两个单独的子系统,它们是动态和静态类型的,它们使用合同样式的编程来帮助导航这两个子系统之间的过渡。这样,该语言可以适应Lisp的用法,在这种情况下,静态类型检查将比帮助更多地成为障碍,以及在静态类型检查将是有利的情况下使用。这是Typed Racket所采用的方法,您将在随后的评论中看到。


16
这个答案有一个基本的问题:您假设静态类型系统必须是HM风格的。此处不能表达的基本概念是子类型化,它是Lisp代码的重要特征。如果您看一下打字的球拍,您会发现它可以轻松表达任何种类的清单-包括诸如(Listof Integer)(Listof Any)。显然,您可能会怀疑后者是无用的,因为您对类型一无所知,但是在TR中,您可以稍后使用它(if (integer? x) ...),并且系统会知道它x是第一个分支中的Integer。
Eli Barzilay 2010年

5
哦,这是打字球拍的错误描述(这与您在某些地方发现的不健全的打字系统不同)。Typed Racket 一种静态类型化语言,对于键入代码没有运行时开销。Racket仍然允许用TR编写一些代码,并使用通常的非类型化语言编写一些代码-在这些情况下,合同(动态检查)用于防止类型化的代码免受潜在错误的非类型化代码的影响。
Eli Barzilay

1
@Eli Barzilay:我撒谎了,它包括四个部分:4.对我而言,很有趣的是,行业认可的C ++编码风格已逐渐从子类型化转向泛型。弱点是该语言不提供声明通用函数将要使用的接口的帮助,某些类型类肯定可以提供帮助。另外,C ++ 0x可能会添加类型推断。我想不是HM,而是朝那个方向爬行?
Owen S.

1
Owen:(1)要点是,您需要子类型来表达lispers编写的代码的类型-HM系统根本无法做到这一点,因此您必须为每种用法自定义类型和构造函数,这使整个事情变得更加尴尬。在有类型的球拍中,使用带有子类型的系统是一个有意设计决策的必然结果:结果应该能够表达这种代码的类型而无需更改代码或创建自定义类型。
Eli Barzilay

1
(2)是的,dynamic类型已在静态语言中流行,这是一种获得动态类型语言好处的解决方法,这些值的通常折衷以使类型可识别的方式包装。但是在这里,类型化的球拍在使语言更方便方面也做得非常好-类型检查器使用谓词的出现来更多地了解类型。例如,请参见球拍页面上的键入示例,并查看如何string?将字符串和数字列表“简化”为字符串列表。
Eli Barzilay

10

我的回答可能没有高度的信心。例如,如果您查看SML之类的语言并将其与Lisp进行比较,则每种语言的功能核心几乎都是相同的。结果,在Lisp的核心(函数应用程序和原始值)上应用某种静态类型似乎并不麻烦。

您的问题的确可以说是完整的,而我看到的其中一些问题是“代码即数据”方法。类型比表达式存在的层次更抽象。Lisp没有这种区别-一切在结构上都是“平坦的”。如果我们考虑某个表达式E:T(其中T是其类型的某种表示形式),然后我们将该表达式视为纯数据,那么T的类型到底是什么?好吧,这是一种!一种是较高的订单类型,所以让我们继续在代码中讲一些有关此的内容:

E : T :: K

您可能会看到我要去的地方。我敢肯定,通过从代码中分离出类型信息,可以避免这种类型的自引用,但是这会使类型的味道不那么“轻浮”。解决这个问题的方法可能有很多,尽管对我来说,最好的方法并不明显。

编辑:哦,所以经过一番谷歌搜索,我发现了Qi,它看起来与Lisp非常相似,只是它是静态类型的。也许这是开始查看他们进行更改以在其中进行静态键入的好地方。


似乎在Qi之后的下一个迭代是Shen,由同一个人开发。
Diagon

4

链接已死。但是无论如何,Dylan不是静态类型的。
比约恩·林德奎斯特(BjörnLindqvist)

@BjörnLindqvist:该链接是关于向Dylan添加渐进式打字的论文。
Rainer Joswig '19

1
@BjörnLindqvist:我链接到概述文件。
Rainer Joswig '19

但是渐进式打字不算作静态打字。如果这样做的话,那么Pypy将是静态类型的Python,因为它也使用了渐进类型。
比昂·林德奎斯特(BjörnLindqvist)

2
@BjörnLindqvist:如果我们通过渐进类型添加静态类型,并且在编译过程中对其进行检查,那么这就是静态类型。并不是整个程序都是静态类型的,而是部分/区域。' homes.sice.indiana.edu/jsiek/what-is-gradual-typing “渐变类型是我于2006年与Walid Taha合作开发的一种类型系统,该系统允许对程序的某些部分进行动态键入,而对其他部分进行静态键入。
Rainer Joswig '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.