У меня есть тип X
, проиндексированный типом S
с несколькими функциями, которые работают с X
. Например, f
преобразует X S1
в X S2
(хотя в этом упрощенном примере X S1
не используется).
{-# LANGUAGE DataKinds, GADTs, TemplateHaskell, TypeFamilies #-}
import Data.Singletons
import Data.Singletons.Sigma
import Data.Singletons.TH
singletons [d|
data S = S1 | S2 | S3 | S4
|]
data X (s :: S) = X
f :: X S1 -> X S2
f x = X
Теперь я хотел бы определить функции, которые могут возвращать X S2
или X S3
в зависимости от аргумента. Простым способом было бы использование Either
.
g1 :: Bool -> X S1 -> Either (X S2) (X S3)
g1 True x = Left X
g1 False x = Right X
Но я не хочу использовать этот подход, потому что мне нужно иметь вложенные Either
, когда функция возвращает больше типов.
Другим подходом было бы использование Sigma
вот так.
g2 :: Bool -> X S1 -> Sigma S (TyCon X)
g2 True x = SS2 :&: X
g2 False x = SS3 :&: X
Но это не выражает идею о том, что g2
возвращает только X S2
или X S3
. Я могу выразить эту идею, введя обертку вокруг X
.
data Y (s :: S) where
Y2 :: X S2 -> Y S2
Y3 :: X S3 -> Y S3
singletons [d|
type Z s = Y s
|]
g3 :: Bool -> X S1 -> Sigma S ZSym0
g3 True x = SS2 :&: Y2 X
g3 False x = SS3 :&: Y3 X
Но затруднительно определять эти оболочки для каждой комбинации и разворачивать их на вызывающих сайтах. Было бы неплохо, если бы я мог напрямую ограничивать типы, используя подход g2
, например, применяя ограничения типов, но я не уверен, как я могу это сделать.
Как я могу напрямую ограничить типы, используя подход g2
?
Я использую GHC 8.8.4 с singletons-2.6.
g :: Bool -> X S1 -> OneOf '[X S2, X S3]
для подходящего определенияOneOf
? - person luqui   schedule 01.10.2020