Answers:
CL类型系统比Haskell 系统更具表现力,例如,您可以(or (integer 1 10) (integer 20 30))
为value 使用类型1,2,...9,10,20,21,...,30
。
但是,Lisp编译器不会强加他们对类型安全性的理解,因此您可以忽略它们的“注释” ,这需要您自担风险。
这意味着您可以通过声明所有值类型并仔细确保推断出所有必需的类型而用Lisp编写Haskell,但是首先可以更轻松地使用Haskell。
基本上,如果要使用强动态类型,请使用Haskell或OCaml,如果要使用强动态类型,请使用Lisp。如果要使用弱静态类型,请使用C;如果要使用弱动态类型,请使用Perl / Python。每条路径都有其优点(和狂热者)和缺点(和and弱者),因此您将从所有这些中受益。
Object
或类型树的根,我可以在大多数静态类型的语言中(详细地)执行相同的操作。这是少的表现,因为你剥夺了的选项说某些变量只能包含一定的值。
类型化球拍与Haskell有很大不同。Lisp和Scheme中的类型系统,以及实际上通常是传统上无类型的语言生态系统中的类型系统,都有一个基本目标,即其他类型的系统不与现有的无类型代码互操作。例如,Typed Racket引入了全新的打字规则,以适应各种Racket习惯用法。考虑以下功能:
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
对于非空列表,这将返回第一个元素。对于空列表,这将返回false。这在无类型语言中很常见;一种类型化的语言会使用类似的包装类型,Maybe
或者在空情况下抛出错误。如果要向此函数添加类型,应使用哪种类型?它不是[a] -> a
(用Haskell表示法),因为它可以返回false。它也不是[a] -> Either a Boolean
,因为(1)在空情况下,它总是返回false,而不是任意布尔值;(2)Either类型将在其中包装元素Left
并在其中添加false,Right
并要求您“拆开任一个”以获取实际元素。相反,该值返回一个真联合-没有包装构造函数,在某些情况下它仅返回一种类型,而在其他情况下仅返回另一种类型。在类型化球拍中,这用联合类型构造函数表示:
(: first (All (A) (-> (Listof A) (U A #f))))
(define (first some-list)
(if (empty? some-list)
#f
(car some-list)))
类型(U A #f)
表示函数可以返回列表的元素,或者返回false,而无需任何包装Either
实例。类型检查器可以推断出some-list
是类型(Pair A (Listof A))
列表还是空列表,此外,它推断出,在if语句的两个分支中,知道是哪种情况。类型检查器知道(car some-list)
表达式中的列表必须具有类型,(Pair A (Listof A))
因为if条件确保了它。这称为出现类型,旨在简化从未键入代码到已键入代码的过渡。
问题是迁移。这里有大量的无类型的Racket代码,而有类型的Racket不能仅仅强迫您放弃所有您喜欢的无类型的库,而是花一个月的时间向您的代码库添加类型。只要将类型逐渐添加到现有代码库中,就会出现此问题,有关这些想法的javascript应用程序,请参阅TypeScript及其任何类型。
渐变类型系统必须提供用于处理常见的无类型习语并与现有的无类型代码进行交互的工具。否则使用它会很痛苦,有关Clojure的示例,请参见“为什么不再使用Core.typed”。