【发布时间】:2019-10-03 21:18:05
【问题描述】:
当我在 Haskell 中有依赖类型时,如何在函数中使用类型中存储的值?我想编写的示例 Haskell 程序(无法编译,因为 min 和 max 类型级别绑定不会扩展到值级别):
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DataKinds #-}
module CharRange (CharRange, ofChar, asChar) where
data CharRange :: Char -> Char -> * where
C :: Char -> CharRange min max
ofChar :: Char -> CharRange min max
ofChar c =
if min <= c && c <= max
then C c
else C min
asChar :: CharRange min max -> Char
asChar (C c) =
if min <= c && c <= max
then c
else min
我可以在 Idris 中做到这一点:
module CharRange
%default total
%access export
data CharRange : Char -> Char -> Type where
C : Char -> CharRange min max
ofChar : Char -> CharRange min max
ofChar c =
if min <= c && c <= max
then C c
else C min
asChar : CharRange min max -> Char
asChar (C c) =
if min <= c && c <= max
then c
else min
按预期编译和工作:
λΠ> the (CharRange 'a' 'z') $ ofChar 'M'
C 'a' : CharRange 'a' 'z'
λΠ> the (CharRange 'a' 'z') $ ofChar 'm'
C 'm' : CharRange 'a' 'z'
如何在不减少类型信息量的情况下将此 Idris 程序翻译成 Haskell?
【问题讨论】:
-
Haskell 没有依赖类型。
-
扩展@chepner 的评论:您绝对可以使用
singletons之类的库以及各种语言特性来模拟 依赖类型。然而,Haskell 本身(还)不支持依赖类型,所以即使你可以非常接近使用它们,你也不能以你尝试使用它们的相同方式实际使用依赖类型。 -
Char类型不包含任何类型(尽管它确实包含许多值)。也就是说,目前写data CharRange :: Char -> Char -> Type是没有用的(顺便说一句,*已弃用,请使用Data.Kind中的Type),因为对于某些x, y :: Char,您永远无法实际构造CharRange x y类型。DataKinds基本上只适用于 ADT,加上(难以忍受的不稳定,IMO)内置插件Nat和Symbol。 -
不,两边都是一样的
Char。值有类型。类型有类型。我们有时会说“善良”这个词,这是一个历史偶然,因为过去有区别,现在没有了。Char是一个充满值但没有类型的类型的示例。Type是一个没有值但充满类型的类型的示例。大多数类型在两边都是相同的。 -
在 Haskell 中,当我们编写
ofChar : forall min max . .....etc etc时,类型级参数min和max在类型检查期间使用,然后在运行时 擦除(不像伊德里斯)。这意味着ofChar在运行时不会收到有关min和max是什么的信息。为了避免这种情况,我们通常求助于singletons,并编写类似ofChar :: forall min max . SChar min -> SChar max -> ....etc etc的内容,其中SChar c是一个“单例”类型,它在运行时保留将丢失的信息。您会在singletons库中找到许多示例。
标签: haskell dependent-type gadt data-kinds