1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE DataKinds #-}
3 {-# LANGUAGE DefaultSignatures #-}
4 {-# LANGUAGE TypeFamilyDependencies #-}
5 {-# LANGUAGE UndecidableInstances #-} -- for type instance defaults
6 module Symantic.CLI.API where
9 import Data.Char (Char)
11 import Data.Function (($), (.), id)
12 import Data.Kind (Constraint)
13 import Data.Maybe (Maybe(..))
14 import Data.String (String)
15 import Text.Show (Show)
19 (<.>) :: repr a b -> repr b c -> repr a c
24 repr a b -> repr b c -> repr a c
25 x <.> y = noTrans (unTrans x <.> unTrans y)
30 (<!>) :: repr a k -> repr b k -> repr (a:!:b) k
31 alt :: repr a k -> repr a k -> repr a k
32 opt :: repr (a->k) k -> repr (Maybe a->k) k
37 repr a k -> repr b k -> repr (a:!:b) k
41 repr a k -> repr a k -> repr a k
45 repr (a->k) k -> repr (Maybe a->k) k
46 x <!> y = noTrans (unTrans x <!> unTrans y)
47 x `alt` y = noTrans (unTrans x `alt` unTrans y)
48 opt = noTrans . opt . unTrans
49 -- NOTE: yes infixr, not infixl like <|>,
50 -- in order to run left-most checks first.
55 -- | Like @(,)@ but @infixr@.
56 data (:!:) a b = a:!:b
61 dimap :: (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k
66 (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k
67 dimap a2b b2a = noTrans . dimap a2b b2a . unTrans
70 class AltApp repr where
71 many0 :: repr (a->k) k -> repr ([a]->k) k
72 many1 :: repr (a->k) k -> repr ([a]->k) k
75 AltApp (UnTrans repr) =>
76 repr (a->k) k -> repr ([a]->k) k
79 AltApp (UnTrans repr) =>
80 repr (a->k) k -> repr ([a]->k) k
81 many0 = noTrans . many0 . unTrans
82 many1 = noTrans . many1 . unTrans
84 -- * Class 'Permutable'
85 class Permutable repr where
86 -- Use @TypeFamilyDependencies@ to help type-inference infer @(repr)@.
87 type Permutation (repr:: * -> * -> *) = (r :: * -> * -> *) | r -> repr
88 type Permutation repr = Permutation (UnTrans repr)
89 runPermutation :: Permutation repr k a -> repr (a->k) k
90 toPermutation :: repr (a->k) k -> Permutation repr k a
91 toPermDefault :: a -> repr (a->k) k -> Permutation repr k a
93 -- | Convenient wrapper to omit a 'runPermutation'.
96 -- opts '<?>' next = 'runPermutation' opts '<.>' next
99 App repr => Permutable repr =>
100 Permutation repr b a -> repr b c -> repr (a->b) c
101 opts <?> next = runPermutation opts <.> next
108 type Segment = String
110 -- * Class 'CLI_Command'
111 class CLI_Command repr where
112 command :: Name -> repr a k -> repr a k
115 class CLI_Var repr where
116 type VarConstraint repr a :: Constraint
117 var' :: VarConstraint repr a => Name -> repr (a->k) k
118 just :: a -> repr (a->k) k
121 type VarConstraint repr a = VarConstraint (UnTrans repr) a
124 CLI_Var (UnTrans repr) =>
125 VarConstraint (UnTrans repr) a =>
126 Name -> repr (a->k) k
129 CLI_Var (UnTrans repr) =>
133 CLI_Var (UnTrans repr) =>
135 var' = noTrans . var'
136 just = noTrans . just
137 nothing = noTrans nothing
139 -- | Like 'var'' but with the type variable @(a)@ first instead or @(repr)@
140 -- so it can be passed using 'TypeApplications' without adding a |\@_| for @(repr)@.
144 VarConstraint repr a =>
145 Name -> repr (a->k) k
150 class CLI_Env repr where
151 type EnvConstraint repr a :: Constraint
152 env' :: EnvConstraint repr a => Name -> repr (a->k) k
154 type EnvConstraint repr a = EnvConstraint (UnTrans repr) a
157 CLI_Env (UnTrans repr) =>
158 EnvConstraint (UnTrans repr) a =>
159 Name -> repr (a->k) k
160 env' = noTrans . env'
162 -- | Like 'env'' but with the type enviable @(a)@ first instead or @(repr)@
163 -- so it can be passed using 'TypeApplications' without adding a |\@_| for @(repr)@.
167 EnvConstraint repr a =>
168 Name -> repr (a->k) k
180 class (App repr, Permutable repr, CLI_Var repr) => CLI_Tag repr where
181 type TagConstraint repr a :: Constraint
182 tagged :: Tag -> repr f k -> repr f k
185 -- tagged n = (tag n <.>)
186 short :: TagConstraint repr a => Char -> repr (a->k) k -> Permutation repr k a
187 short n = toPermutation . tagged (TagShort n)
188 long :: TagConstraint repr a => Name -> repr (a->k) k -> Permutation repr k a
189 long n = toPermutation . tagged (TagLong n)
191 option :: TagConstraint repr a => a -> repr (a->k) k -> Permutation repr k a
192 option = toPermDefault
193 flag :: TagConstraint repr Bool => Tag -> Permutation repr k Bool
194 flag n = toPermDefault False $ tagged n $ just True
195 shortOpt :: TagConstraint repr a => Char -> a -> repr (a->k) k -> Permutation repr k a
196 shortOpt n a = toPermDefault a . tagged (TagShort n)
197 longOpt :: TagConstraint repr a => Name -> a -> repr (a->k) k -> Permutation repr k a
198 longOpt n a = toPermDefault a . tagged (TagLong n)
201 type TagConstraint repr a = TagConstraint (UnTrans repr) a
204 CLI_Tag (UnTrans repr) =>
205 Tag -> repr f k -> repr f k
208 CLI_Tag (UnTrans repr) =>
210 tagged n = noTrans . tagged n . unTrans
211 endOpts = noTrans endOpts
213 -- * Class 'CLI_Response'
214 class CLI_Response repr where
215 type ResponseConstraint repr a :: Constraint
216 type ResponseArgs repr a :: * -- = (r:: *) | r -> a
217 type Response repr :: *
219 ResponseConstraint repr a =>
220 repr (ResponseArgs repr a)
223 type ResponseConstraint repr a = ResponseConstraint (UnTrans repr) a
224 type ResponseArgs repr a = ResponseArgs (UnTrans repr) a
225 type Response repr = Response (UnTrans repr)
229 CLI_Response (UnTrans repr) =>
230 ResponseConstraint (UnTrans repr) a =>
231 ResponseArgs repr a ~ ResponseArgs (UnTrans repr) a =>
232 Response repr ~ Response (UnTrans repr) =>
233 repr (ResponseArgs repr a)
235 response' = noTrans (response' @_ @a)
240 ResponseConstraint repr a =>
241 repr (ResponseArgs repr a)
243 response = response' @repr @a
244 {-# INLINE response #-}
246 -- * Class 'CLI_Help'
247 class CLI_Help repr where
248 type HelpConstraint repr d :: Constraint
249 help :: HelpConstraint repr d => d -> repr f k -> repr f k
251 program :: Name -> repr f k -> repr f k
252 rule :: Name -> repr f k -> repr f k
254 type HelpConstraint repr d = HelpConstraint (UnTrans repr) d
257 CLI_Help (UnTrans repr) =>
258 Name -> repr f k -> repr f k
261 CLI_Help (UnTrans repr) =>
262 Name -> repr f k -> repr f k
263 program n = noTrans . program n . unTrans
264 rule n = noTrans . rule n . unTrans
268 class Trans repr where
269 -- | The @(repr)@esentation that @(repr)@ 'Trans'forms.
270 type UnTrans repr :: * -> * -> *
271 -- | Lift the underlying @(repr)@esentation to @(repr)@.
272 -- Useful to define a combinator that does nothing in a 'Trans'formation.
273 noTrans :: UnTrans repr a b -> repr a b
274 -- | Unlift a @(repr)@esentation. Useful when a 'Trans'formation
275 -- combinator needs to access the 'UnTrans'formed @(repr)@esentation,
276 -- or at the end to get the underlying 'UnTrans'formed @(repr)@esentation
277 -- from the inferred @(repr)@ value (eg. in 'server').
278 unTrans :: repr a b -> UnTrans repr a b