所以在伊德里斯写下以下内容是完全有效的。
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不允许值泄漏到类型级别?
答案 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的计划是维护和分离pi
和forall
,分别支持参数和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
因此can写item b
,但这仍然不会影响控制流程,因为所有的决定都是在之前做出的运行)。 .
的具体类型在运行时并不重要。
然而,正如pigworker所说,它不一定是参数类型。并且它不一定是值的非参数。类型级 - 值级和参数 - 非参数是完全正交的二分法。有关详细信息,请参阅this答案。
因此,Haskell和Idris在处理运行/编译内容的价值水平方面有所不同(因为在Idris中你可以用{{1}}标记一个参数以使其可以删除),但是它们大致相同地处理类型方式。