Преобразование GADT без ограничений в другой GADT с ограничениями, когда такие ограничения выполняются
Можем ли мы преобразовать GADT без заданного ограничения на его конструкторы в GADT, который имеет указанное ограничение? Я хочу сделать это, потому что я хочу получить глубокое вложение Arrows и сделать некоторые интересные вещи с представлением, которое (на данный момент), кажется, требует Typeable
, ( Одна из причин)
data DSL a b where
Id :: DSL a a
Comp :: DSL b c -> DSL a b -> DSL a c
-- Other constructors for Arrow(Loop,Apply,etc)
data DSL2 a b where
Id2 :: (Typeable a, Typeable b) => DSL2 a a
Comp2 :: (Typeable a, Typeable b, Typeable c) => DSL2 b c -> DSL2 a b -> DSL2 a c
-- ...
Мы могли бы попробовать следующее from
функционировать, но это быстро ломается, так как у нас нетTypeable
информация для рекурсивной точки
from :: (Typeable a, Typeable b) => DSL a b -> DSL2 a b
from (Id) = Id2
from (Comp g f) = Comp2 (from g) (from f)
Поэтому вместо этого мы пытаемся зафиксировать преобразование в классе типов. Тем не менее, это сломается, так как мы будем упускать Typeable b
информация как b
является экзистенциальным
class From a b where
from :: a -> b
instance (Typeable a, Typeable b) => From (DSL a b) (DSL2 a b) where
from (Id) = Id2
from (Comp g f) = Comp2 (from g) (from f)
Любые другие предложения? В конечном итоге я хочу создать глубокое вложение Category
а также Arrow
вместе с Typeable
информация о параметрах типа. Это так, чтобы я мог использовать синтаксис стрелки для создания значения в моем DSL и иметь довольно стандартный код на Haskell. Может быть, я должен прибегнуть к шаблону Haskell?
2 ответа
Проблема с рекурсивным случаем фатальна для трансформации DSL a b
в DSL2 a b
,
Для этого преобразования потребуется найти Typeable
словарь для экзистенциального типа b
в Comp
дело - но что b
на самом деле это уже забыто.
Например, рассмотрим следующую программу:
data X = X Int
-- No Typeable instance for X
dsl1 :: DSL X Char
dsl1 = -- DSL needs to have some way to make non-identity terms,
-- use whatever mechanism it offers for this.
dsl2 :: DSL Int X
dsl2 = -- DSL needs to have some way to make non-identity terms,
-- use whatever mechanism it offers for this.
v :: DSL Int Char
v = Comp dsl1 dsl2
v2 :: DSL2 Int Char
v2 = -- made by converting v from DSL to DSL2, note that Int and Char are Typeable
typeOfIntermediate :: DSL a c -> TypeRep
typeOfIntermediate int =
case int of
Comp (bc :: DSL2 b c) (ab :: DSL2 a b) ->
typeOf (undefined :: b)
typeOfX = typeOfIntermediate v2
Другими словами, если бы был способ сделать преобразование в целом, вы могли бы как-то изобрести Typeable
экземпляр для типа, который на самом деле не имеет такового.
В конечном итоге я хочу создать глубокое вложение
Category
а такжеArrow
вместе сTypeable
информация о параметрах типа. Это так, чтобы я мог использовать синтаксис стрелки для создания значения в моем DSL и иметь довольно стандартный код на Haskell.
Возможно, вам следует прибегнуть к {-# LANGUAGE RebindableSyntax #-}
(отмечая, что это подразумевает NoImplicitPrelude
). Создайте свой собственный arr
, (>>>)
, first
, app
, (|||)
а также loop
функции и GHC будут использовать их при удалении обозначений стрелок вместо стандартных версий из Control.Arrow.
В руководстве говорится, что "типы этих функций должны очень близко соответствовать типам Prelude". Если вы строите параллельную иерархию классов (копию иерархии в Control.Arrow, но с Typeable
ограничения добавляются к типу подписей) у вас должно быть все в порядке.
(Примечание: я не знаком со стрелочной нотацией, поэтому никогда не использовал ее в сочетании с RebindableSyntax; мой ответ - разумное предположение.)