1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE ConstraintKinds #-}
3 {-# LANGUAGE DataKinds #-}
4 {-# LANGUAGE UndecidableInstances #-}
6 -- | Tuples-of-Functions
7 module Symantic.Syntaxes.TuplesOfFunctions where
9 import Data.Bool (Bool (..))
10 import Data.Either (Either (..))
12 import Data.Function qualified as Fun
13 import Data.Kind (Type)
14 import Text.Show (Show)
15 import Type.Reflection ((:~:) (..))
18 type ToF a next = ToFIf (IsToF a) a next
22 -- | Transform a type @(a)@ to Tuples-of-Functions returning @(next)@.
23 -- The @(t)@ parameter is to avoid overlapping instances of 'UnToFIf'.
24 type family ToFIf t a next :: Type where
26 ToFIf 'True (a, b) next = ToF a (ToF b next)
27 -- For '<+>', request both branches.
28 ToFIf 'True (Either l r) next = (ToF l next, ToF r next)
29 -- Useless to ask '()' as argument.
30 ToFIf 'True () next = next
31 -- Enable a different return value for each function.
32 ToFIf 'True (Endpoint end a) next = (next :~: end, a)
33 -- Everything else becomes a new argument.
34 ToFIf 'False a next = a -> next
38 -- | This 'Bool' is added to 'ToFIf' to avoid overlapping instances.
39 type family IsToF a :: Bool where
42 IsToF (Either l r) = 'True
43 IsToF (Endpoint end a) = 'True
47 newtype Endpoint end a = Endpoint {unEndpoint :: a}
50 endpoint :: a -> ToF (Endpoint end a) end
54 type UnToF a = UnToFIf (IsToF a) a
57 class UnToFIf (t :: Bool) a where
58 unToF :: ToFIf t a next -> a -> next
59 instance UnToFIf 'True () where
61 instance (UnToF a, UnToF b) => UnToFIf 'True (a, b) where
62 unToF hab (a, b) = (unToF @(IsToF b) (unToF @(IsToF a) hab a)) b
63 instance (UnToF a, UnToF b) => UnToFIf 'True (Either a b) where
64 unToF (ha, hb) = \case
65 Left a -> unToF @(IsToF a) ha a
66 Right b -> unToF @(IsToF b) hb b
67 instance UnToFIf 'False a where