繁体   English   中英

在类型声明中键入限制

[英]Type restriction in type declaration

有一个着名的类型级自然数的例子:

data Zero
data Succ n

当我们应用类型构造函数Succ时,我有一个关于理想限制的问题。 例如,如果我们想在函数定义中进行这样的限制,我们可以使用类和上下文,就像在这段代码中一样:

class Nat n where
  toInt :: n -> Int
instance Nat Zero where
  toInt _ = 0
instance (Nat n) => Nat (Succ n) where
  toInt _ = 1 + toInt (undefined :: n)

使用toInt (undefined :: Succ Int)是不可能的,没关系。

但是如何在类型级别构造上实现类似的限制(可能有一些高级类型扩展)?

例如,我想允许使用类型构造函数Succ只使用类型Zero和类似的东西: Succ (Succ Zero)Succ (Succ (Succ Zero))等等。 如何在编译时避免这样的坏例子:

type Test = Succ Int

(目前,没有编译错误)

PS:对我来说,如何对最后一个样本的类型声明创建限制更有意思

如今,我们使用DataKinds扩展:

{-# LANGUAGE DataKinds, KindSignatures, ScopedTypeVariables #-}

-- N is a type, but is also a kind now
-- Zero, Succ Zero, ... are values, but are also type-level values of
-- kind N
data N = Zero | Succ N

-- (We could import Proxy the library, instead)
data Proxy (n :: N) = Proxy

-- Now n is restricted to kind N
class Nat (n :: N) where
  toInt :: proxy n -> Int

instance Nat Zero where
  toInt _ = 0
instance (Nat n) => Nat (Succ n) where
  toInt _ = 1 + toInt (undefined :: Proxy n)

然后我们可以使用toInt (Proxy :: Proxy (Succ Zero)) 相反, toInt (Proxy :: Proxy (Succ Int))会根据需要引发类型错误。

就个人而言,我也将取代更现代的东西,如代理AllowAmbiguousTypesTypeApplications所以删除未使用的参数。

{-# LANGUAGE DataKinds, KindSignatures, ScopedTypeVariables,
             AllowAmbiguousTypes, TypeApplications #-}

data N = Zero | Succ N

-- Now n is restricted to kind N
class Nat (n :: N) where
  toInt :: Int

instance Nat Zero where
  toInt = 0
instance (Nat n) => Nat (Succ n) where
  toInt = 1 + toInt @n

使用它作为toInt @(Succ Zero) toInt @n语法选择类型类中的n 它不对应于在运行时交换的任何值,只是在编译时存在的类型级参数。


运用

type Foo = Succ Int

也想要错误:

    • Expected kind ‘N’, but ‘Int’ has kind ‘*’
    • In the first argument of ‘Succ’, namely ‘Int’
      In the type ‘Succ Int’
      In the type declaration for ‘Foo’

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM