Haskell和Idris之间的区别:类型Universe中运行时/编译时的反映

时间:2016-05-21 11:31:36

标签: haskell dependent-type idris type-level-computation

所以在伊德里斯写下以下内容是完全有效的。

item : (b : Bool) -> if b then Nat else List Nat
item True  = 42
item False = [1,2,3] // cf. https://www.youtube.com/watch?v=AWeT_G04a0A

没有类型签名,这看起来像一个动态类型语言。但实际上,伊德里斯是依赖性的。 item b的具体类型只能在运行时确定。

当然,这是一位Haskell程序员在谈论:Idris意义上item b的类型是在编译期间给出的,它是if b then Nat ...

现在我的问题:我是否正确地得出结论,在Haskell中,运行时和编译时之间的边界恰好在值的世界(False,“foo”,3)和类型的世界之间运行(Bool,String,整数)而在Idris中,运行时和编译时之间的边界跨越了宇宙?

另外,我是正确的假设即使在Haskell中使用依赖类型(使用DataKinds和TypeFamilies,参见this article),上面的例子在Haskell中也是不可能的,因为与Idris相反的Haskell不允许值泄漏到类型级别?

2 个答案:

答案 0 :(得分:28)

是的,您是正确的观察到Idris中的类型与值的区别与仅编译时与运行时和编译时的区别不一致。这是好事。具有仅在编译时存在的值是有用的,就像在程序逻辑中一样,我们只有在规范中使用的“鬼变量”。在运行时使用类型表示也很有用,允许数据类型泛型编程。

在Haskell中,PolyKinds(和type family Cond (b :: Bool)(t :: k)(e :: k) :: k where Cond 'True t e = t Cond 'False t e = e )让我们写

item :: pi (b :: Bool) -> Cond b Int [Int]
item True  = 42
item False = [1,2,3]

并且在不久的将来,我们将能够写出

data Booly :: Bool -> * where
  Truey  :: Booly 'True
  Falsey :: Booly 'False

item :: forall b. Booly b -> Cond b Int [Int]
item Truey  = 42
item Falsey = [1,2,3]

但是在实现该技术之前,我们必须处理依赖函数类型的单例伪造,如下所示:

forall

你可以在这种伪装方面走得很远,但如果我们真的有这件事,那么这一切都会变得容易多了。

至关重要的是,Haskell的计划是维护和分离piforall,分别支持参数和ad hoc多态。与pi一起使用的lambdas和应用程序仍然可以在运行时代码生成中删除,就像现在一样,但pi x :: * -> ...的那些被保留。拥有运行时类型抽象Data.Typeable并将复杂性为{{1}}的老鼠窝扔进垃圾箱也是有意义的。

答案 1 :(得分:9)

  

现在我的问题:我是否正确地在Haskell,边界   运行时和编译时之间正好在世界之间运行   值(False," foo",3)和类型世界(Bool,String,   整数)而在Idris中,运行时和运行时之间的边界   编译时跨越宇宙?

Idris编译为Epic (更新:不,它不再编译为Epis,因为 Spearman 在下面的评论中说明):

  

除了查看名称是否在范围内之外,没有语义检查 - 它   假设更高级别的语言将会执行   类型检查,无论如何,Epic不应该做任何假设   更高级别的类型系统或您应用的任何转换。   类型注释是必需的,但它们只给出提示   编译器(我可能会改变它)。

因此,类型在指称上无关紧要,即术语的含义并不取决于其类型。此外,可以擦除一些有价值的东西,例如,在Vect n A中(其中Vect是具有静态已知长度的列表类型)n(长度)可以删除,because

  

Brady,McBride和McKinna在BMM04中描述了一些方法   从数据结构中删除索引,利用这一事实   对它们进行操作的函数要么已经有了它的副本   如果需要,可以快速重建适当的索引或索引。

这里的事情是,Idris中的pi以与Haskell中的forall几乎相同的方式处理类型:在这种情况下,它们都是参数的(尽管这些参数是不同的)。编译器可以使用类型来优化代码,但在两种语言中,控制流程并不依赖于类型,即您不能说if A == Int then ... else ...(但是,如果A是规范形式的话,然后你静静地知道它是Int是否A == Int因此canitem b,但这仍然不会影响控制流程,因为所有的决定都是在之前做出的运行)。 .的具体类型在运行时并不重要。

然而,正如pigworker所说,它不一定是参数类型。并且它不一定是值的非参数。类型级 - 值级和参数 - 非参数是完全正交的二分法。有关详细信息,请参阅this答案。

因此,Haskell和Idris在处理运行/编译内容的价值水平方面有所不同(因为在Idris中你可以用{{1}}标记一个参数以使其可以删除),但是它们大致相同地处理类型方式。