如何将数据类型带到值级别?
How to bring a data kind to the value level?
我的代码中有这样的东西:
data SomeKind = Kind1 | Kind2 deriving Eq
data SomeValue (t :: SomeKind) = SomeValue
someValue1 :: SomeValue Kind1
someValue1 = SomeValue
someValue2 :: SomeValue Kind2
someValue2 = SomeValue
我想将类型级别的类型转换为值级别,可能是这样的:
valueKind :: SomeValue a -> SomeKind
那将:
valueKind someValue1 == Kind1
valueKind someValue2 == Kind2
可以吗?
valueKind :: SomeValue a -> SomeKind
是不可能的。 a
类型参数不会以任何形式出现在运行时,因此我们无法对其进行分支。
在运行时和编译时使用类型的标准方法是创建所谓的单例类型。单例由原始类型的类型级版本索引,并且具有 属性 我们可以通过对它们进行模式匹配来揭示索引:
data SSomeKind (i :: SomeKind) where
SKind1 :: SSomeKind Kind1
SKind2 :: SSomeKind Kind2
它们被称为单例是因为对于每个类型索引只有一个值。同样,对于每个值,只有一个类型索引选择。这种对应关系让我们可以使用 SSomeKind
作为 SomeKind
的运行时表示。
valueKind' :: SSomeKind a -> SomeKind
valueKind' SKind1 = Kind1
valueKind' SKind2 = Kind2
创建单例定义和关联的升降函数是一项相当机械的工作。 singletons
库对其进行了自动化和简化。在我们的例子中:
{-# LANGUAGE TemplateHaskell, DataKinds, GADTs, TypeFamilies, ScopedTypeVariables #-}
import Data.Singletons.TH
$(singletons [d| data SomeKind = Kind1 | Kind2 |])
-- generates a lot of stuff, including the SSomeKind definition.
-- works the same as our previously defined function
valueKind' :: SSomeKind a -> SomeKind
valueKind' = fromSing
-- we can also polymorphically get specific singleton values:
foo :: Sing Kind1
foo = sing -- now foo equals SKind1
图书馆里还有很多。请参阅 this page 以获取快速入门和更多参考。
您可以定义一个类型-class,returns 关联值基于类型参数。
class ValueKind (t :: SomeKind) where
valueKind :: f t -> SomeKind
instance ValueKind Kind1 where
valueKind _ = Kind1
instance ValueKind Kind2 where
valueKind _ = Kind2
如果您可以容忍类型 class 约束,这可以通过 SomeKind
中每种类型的实例来实现。这与 Kindable
类型非常相似 class
class SomeKindable (k :: SomeKind) where
someKindOf :: p k -> SomeKind
instance SomeKindable Kind1 where
someKindOf _ = Kind1
instance SomeKindable Kind2 where
someKindOf _ = Kind2
valueKind :: SomeKindable a => SomeValue a -> SomeKind
valueKind = someKindOf
编译器无法判断所有 k :: SomeKind
都有一个 SomeKindable k
实例。如果您需要它对每个 SomeValue
都可用而无法显示 SomeKindable
,您可以将该值与 SomeKindable
字典一起打包在 GADT
.[=20 中=]
{-# LANGUAGE GADTs #-}
data SomeValue (t :: SomeKind) where
SomeValue :: SomeKindable t => SomeValue t
valueKind :: SomeValue a -> SomeKind
valueKind (p@SomeValue) = someKindOf p
我的代码中有这样的东西:
data SomeKind = Kind1 | Kind2 deriving Eq
data SomeValue (t :: SomeKind) = SomeValue
someValue1 :: SomeValue Kind1
someValue1 = SomeValue
someValue2 :: SomeValue Kind2
someValue2 = SomeValue
我想将类型级别的类型转换为值级别,可能是这样的:
valueKind :: SomeValue a -> SomeKind
那将:
valueKind someValue1 == Kind1
valueKind someValue2 == Kind2
可以吗?
valueKind :: SomeValue a -> SomeKind
是不可能的。 a
类型参数不会以任何形式出现在运行时,因此我们无法对其进行分支。
在运行时和编译时使用类型的标准方法是创建所谓的单例类型。单例由原始类型的类型级版本索引,并且具有 属性 我们可以通过对它们进行模式匹配来揭示索引:
data SSomeKind (i :: SomeKind) where
SKind1 :: SSomeKind Kind1
SKind2 :: SSomeKind Kind2
它们被称为单例是因为对于每个类型索引只有一个值。同样,对于每个值,只有一个类型索引选择。这种对应关系让我们可以使用 SSomeKind
作为 SomeKind
的运行时表示。
valueKind' :: SSomeKind a -> SomeKind
valueKind' SKind1 = Kind1
valueKind' SKind2 = Kind2
创建单例定义和关联的升降函数是一项相当机械的工作。 singletons
库对其进行了自动化和简化。在我们的例子中:
{-# LANGUAGE TemplateHaskell, DataKinds, GADTs, TypeFamilies, ScopedTypeVariables #-}
import Data.Singletons.TH
$(singletons [d| data SomeKind = Kind1 | Kind2 |])
-- generates a lot of stuff, including the SSomeKind definition.
-- works the same as our previously defined function
valueKind' :: SSomeKind a -> SomeKind
valueKind' = fromSing
-- we can also polymorphically get specific singleton values:
foo :: Sing Kind1
foo = sing -- now foo equals SKind1
图书馆里还有很多。请参阅 this page 以获取快速入门和更多参考。
您可以定义一个类型-class,returns 关联值基于类型参数。
class ValueKind (t :: SomeKind) where
valueKind :: f t -> SomeKind
instance ValueKind Kind1 where
valueKind _ = Kind1
instance ValueKind Kind2 where
valueKind _ = Kind2
如果您可以容忍类型 class 约束,这可以通过 SomeKind
中每种类型的实例来实现。这与 Kindable
类型非常相似 class
class SomeKindable (k :: SomeKind) where
someKindOf :: p k -> SomeKind
instance SomeKindable Kind1 where
someKindOf _ = Kind1
instance SomeKindable Kind2 where
someKindOf _ = Kind2
valueKind :: SomeKindable a => SomeValue a -> SomeKind
valueKind = someKindOf
编译器无法判断所有 k :: SomeKind
都有一个 SomeKindable k
实例。如果您需要它对每个 SomeValue
都可用而无法显示 SomeKindable
,您可以将该值与 SomeKindable
字典一起打包在 GADT
.[=20 中=]
{-# LANGUAGE GADTs #-}
data SomeValue (t :: SomeKind) where
SomeValue :: SomeKindable t => SomeValue t
valueKind :: SomeValue a -> SomeKind
valueKind (p@SomeValue) = someKindOf p