存在类型包装器的库

时间:2017-01-26 03:26:46

标签: haskell gadt

让我们说我得到了以下内容:

data T a

f :: a -> (exists t. T t)
g :: T b -> c

h :: a -> c
h = g . f

据我所知,f的类型签名无效Haskell。相反,我可以这样做:

{-# LANGUAGE GADTs #-}

data T a

data ExistsTA where
  ExistsTA :: T a -> ExistsTA

f :: a -> ExistsTA
g :: T b -> c

h :: a -> c
h x = case (f x) of ExistsTA x' -> g x'

编译好。我想知道,是否有一个库可以概括ExistsTA数据类型的创建(可能需要T作为参数),或者每次我想要这样做时都必须自己滚动(这个这不是什么大问题,如果我不需要,也不想重新发明轮子。

特别是对于我的应用程序,我还希望以这种形式包装:

data C where
  C1 :: C
  ...

data D (a :: C) where
  D1 a :: D
  ...

data T (d :: D) a

f :: T (D1 C1) a -> exists c. T (D1 c) a

1 个答案:

答案 0 :(得分:3)

我不知道这是否在任何地方的图书馆,但我喜欢使用以下通用存在:

data Ex f = forall a. Ex (f a)

使用PolyKinds Ex可以存在包装任何类型f :: k -> *的参数。这是多么通用?我们可以操纵f直到它是正确的形状,我们可以使用一个类型的组合器库来构建我们需要的任何额外信息。使用像这样的通用类型是一种强大的编程方式,但通常只需要自己编写就可以了。

假设我们想要对两参数类型p的两半进行存在量化。可以使用以下GADT 取消发送 p,将其从双参数类型k1 -> k2 -> *转换为单参数类型(k1, k2) -> *

data Uncurry p ij where
    Uncurry :: { getUncurry :: p i j } -> Uncurry p '(i, j)

现在Uncurry p可以存在包裹。

type ExP p = Ex (Uncurry p)

假设我想将我的存在包裹类型与一些证据(例如单例)配对,以便可以恢复存在量化的索引。我会使用与索引相关的产品来配对两个仿函数fg

newtype (f :*: g) i = f i :*: g i

如果,f是GADT,f上的模式匹配 - 对的一半会告诉您g的索引。现在,f :*: g有适当的存在包裹。

type ExPair f g = Ex (f :*: g)

在实践中,您可以编写ExPair Sing f以将f与单身人士配对。

假设我需要约束形式的上述证据。我可以使用以下类型将Sing从上面替换为c a的实例字典作为(可见)运行时值:

data Dict1 c a where
    Dict1 :: c a => Dict1 c a

(或者你可以使用the constraints packagenewtype Dict1 c a = Dict1 { getDict1 :: Dict (c a) }。)现在我只需要将我的对的左手部分设置为Dict1 c

type ExDictPair c f = ExPair (Dict1 c) f

因此,您可以编写ExDictPair SingI f来打包隐式单例。

假设我需要存在量化的东西是更高的类型,例如* -> *。 (我可能想谈谈“包含Monad”的Int的某个实例。)Ex是多边形的,但它只是存在量化其参数的最右边参数。所以我们需要类型的* -> *部分作为我们数据类型的最后一个参数。我也可以为它写一个类型组合器:

newtype RApp a f = RApp { getRApp :: f a }

type SomeMonadAppliedToInt = ExDictPair Monad (RApp Int)