Это выглядит невозможным, по крайней мере, с текущим GH C. Предположим, что у вашего Payload A
было то же представление Int
и т. Д.
data Tag = A | B | C
data Payload (tag :: Tag) where
PA :: Int -> Payload A
PB :: Double -> Payload B
PC :: Bool -> Payload C
Тогда как нам это реализовать?
foo :: Payload tag -> Int
foo (PA i) = i
foo (PB _) = 1
foo (PC _) = 2
Для реализации foo
, нам как-то нужно извлечь tag
из Payload tag
, но это невозможно, если Payload tag
не хранит тег в его представлении.
Вместо этого мы могли бы отделить среду выполнения представление тега из его полезных данных.
type family Payload (tag :: Tag) where
Payload 'A = Int
Payload 'B = Double
Payload 'C = Bool
Теперь Payload 'A
- это точно Int
. Однако мы теряем возможность писать foo
, поскольку тег больше не сохраняется во время выполнения вдоль полезной нагрузки. Вместо этого мы можем написать это:
-- singleton, could be auto-generated using the singletons library
data STag (tag :: Tag) where
SA :: STag 'A
SB :: STag 'B
SC :: STag 'C
bar :: STag tag -> Payload tag -> Int
bar PA i = i
bar PB _ = 1
bar PC _ = 2
Обратите внимание, как мы по существу добавляем тег в качестве аргумента, поскольку нам нужно, чтобы он был представлен во время выполнения.