让我们说我得到了以下内容:
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
答案 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)
假设我想将我的存在包裹类型与一些证据(例如单例)配对,以便可以恢复存在量化的索引。我会使用与索引相关的产品来配对两个仿函数f
和g
:
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
package:newtype 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)