Преобразование 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; мой ответ - разумное предположение.)

Другие вопросы по тегам