Я не знаю, является ли это в библиотеке в любом месте, но я хотел бы использовать следующее общее назначение экзистенциальным:
data Ex f = forall a. Ex (f a)
с PolyKinds
Ex
может экзистенциально завернуть параметр любого типа f :: k -> *
. Как это общего? Мы можем манипулировать f
до тех пор, пока это не будет правильной формой, и мы сможем создать любую дополнительную информацию, которая нам нужна, с небольшой библиотекой комбинаторов типов. Работа с такими типами общего назначения, как это, является мощным способом программирования, но часто проще просто сворачивать свои собственные.
Предположим, что мы хотим, чтобы экзистенциально количественно обе половинки типа два параметра p
. Можно использовать следующий GADT до uncurryp
, превратив его из двухпараметрического типа 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) }
) Теперь мне просто нужно, чтобы установить левые -hand часть моей пары быть 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)