@@ -1,3 +1,6 @@
1+{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE TypeOperators #-}
3+{-# LANGUAGE UndecidableInstances #-}
1module Servant.API (
4module Servant.API (
3 -- * Combinators
6 -- * Combinators
@@ -43,6 +46,9 @@ module Servant.API (
43 module Servant.Common.Text,
46 module Servant.Common.Text,
44 -- | Classes and instances for types that can be converted to and from @Text@
47 -- | Classes and instances for types that can be converted to and from @Text@
49+ -- * Canonicalizing (flattening) API types
46 -- * Utilities
52 -- * Utilities
47 module Servant.Utils.Links,
53 module Servant.Utils.Links,
48 -- | Type-safe internal URIs
54 -- | Type-safe internal URIs
@@ -69,3 +75,25 @@ import Servant.API.ReqBody (ReqBody)
69import Servant.API.Sub ((:>))
75import Servant.API.Sub ((:>))
70import Servant.Utils.Links (HasLink (..), IsElem, IsElem',
76import Servant.Utils.Links (HasLink (..), IsElem, IsElem',
71 URI (..), safeLink)
77 URI (..), safeLink)
79+-- | Turn an API type into its canonical form.
81+-- The canonical form is defined and will basically turn:
83+-- > "hello" :> (Get Hello :<|> ReqBody Hello :> Put Hello)
87+-- > ("hello" :> Get Hello) :<|> ("hello" :> ReqBody Hello :> Put Hello)
89+-- i.e distributing all ':>'-separated bits into the subsequent ':<|>'s.
90+type family Canonicalize api :: * where
91+ -- requires UndecidableInstances
92+ Canonicalize (a :> (b :<|> c)) = ((a :> Canonicalize b) :<|> (a :> Canonicalize c))
93+ Canonicalize (a :> b) = Redex b (Canonicalize b) a
94+ Canonicalize (a :<|> b) = Canonicalize a :<|> Canonicalize b
97+type family Redex a b c :: * where
98+ Redex a a first = Canonicalize first :> a
99+ Redex a b first = Canonicalize (first :> b)