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
8 import Control.Applicative (Applicative(..), Alternative(..))
9 import Control.Monad (Monad(..))
11 import Data.Char (Char)
13 import Data.Function (($), (.), id)
15 import Data.Kind (Constraint)
16 import Data.Maybe (Maybe(..), maybe)
17 import Data.Monoid (Monoid)
18 import Data.String (String)
19 import Data.Text (Text)
20 import Text.Show (Show)
21 import Data.Functor (Functor(..), (<$>))
25 (<.>) :: repr a b -> repr b c -> repr a c
30 repr a b -> repr b c -> repr a c
31 x <.> y = noTrans (unTrans x <.> unTrans y)
36 (<!>) :: repr a k -> repr b k -> repr (a:!:b) k
41 repr a k -> repr b k -> repr (a:!:b) k
42 x <!> y = noTrans (unTrans x <!> unTrans y)
43 opt :: repr (a->k) k -> repr (Maybe a->k) k
47 -- | Like @(,)@ but @infixr@.
48 data (:!:) a b = a:!:b
53 dimap :: (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k
58 (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k
59 dimap a2b b2a = noTrans . dimap a2b b2a . unTrans
62 class AltApp repr where
63 many0 :: repr (a->k) k -> repr ([a]->k) k
64 many1 :: repr (a->k) k -> repr ([a]->k) k
67 AltApp (UnTrans repr) =>
68 repr (a->k) k -> repr ([a]->k) k
71 AltApp (UnTrans repr) =>
72 repr (a->k) k -> repr ([a]->k) k
73 many0 = noTrans . many0 . unTrans
74 many1 = noTrans . many1 . unTrans
76 -- * Class 'Permutable'
77 class Permutable repr where
78 -- Use @TypeFamilyDependencies@ to help type-inference infer @(repr)@.
79 type Permutation (repr:: * -> * -> *) = (r :: * -> * -> *) | r -> repr
80 type Permutation repr = Permutation (UnTrans repr)
81 runPermutation :: Permutation repr k a -> repr (a->k) k
82 toPermutation :: repr (a->k) k -> Permutation repr k a
83 toPermDefault :: a -> repr (a->k) k -> Permutation repr k a
85 -- | Convenient wrapper to omit a 'runPermutation'.
88 -- opts '<?>' next = 'runPermutation' opts '<.>' next
91 App repr => Permutable repr =>
92 Permutation repr b a -> repr b c -> repr (a->b) c
93 opts <?> next = runPermutation opts <.> next
100 type Segment = String
102 -- * Class 'CLI_Command'
103 class CLI_Command repr where
104 command :: Name -> repr a k -> repr a k
107 class CLI_Var repr where
108 type VarConstraint repr a :: Constraint
109 var' :: VarConstraint repr a => Name -> repr (a->k) k
110 just :: a -> repr (a->k) k
113 type VarConstraint repr a = VarConstraint (UnTrans repr) a
116 CLI_Var (UnTrans repr) =>
117 VarConstraint (UnTrans repr) a =>
118 Name -> repr (a->k) k
121 CLI_Var (UnTrans repr) =>
125 CLI_Var (UnTrans repr) =>
127 var' = noTrans . var'
128 just = noTrans . just
129 nothing = noTrans nothing
131 -- | Like 'var'' but with the type variable @(a)@ first instead or @(repr)@
132 -- so it can be passed using 'TypeApplications' without adding a |\@_| for @(repr)@.
136 VarConstraint repr a =>
137 Name -> repr (a->k) k
142 class CLI_Env repr where
143 type EnvConstraint repr a :: Constraint
144 env' :: EnvConstraint repr a => Name -> repr (a->k) k
146 type EnvConstraint repr a = EnvConstraint (UnTrans repr) a
149 CLI_Env (UnTrans repr) =>
150 EnvConstraint (UnTrans repr) a =>
151 Name -> repr (a->k) k
152 env' = noTrans . env'
154 -- | Like 'env'' but with the type enviable @(a)@ first instead or @(repr)@
155 -- so it can be passed using 'TypeApplications' without adding a |\@_| for @(repr)@.
159 EnvConstraint repr a =>
160 Name -> repr (a->k) k
172 class (App repr, Permutable repr, CLI_Var repr) => CLI_Tag repr where
173 type TagConstraint repr a :: Constraint
174 tagged :: Tag -> repr f k -> repr f k
177 -- tagged n = (tag n <.>)
178 short :: TagConstraint repr a => Char -> repr (a->k) k -> Permutation repr k a
179 short n = toPermutation . tagged (TagShort n)
180 long :: TagConstraint repr a => Name -> repr (a->k) k -> Permutation repr k a
181 long n = toPermutation . tagged (TagLong n)
183 option :: TagConstraint repr a => a -> repr (a->k) k -> Permutation repr k a
184 option = toPermDefault
185 flag :: TagConstraint repr Bool => Tag -> Permutation repr k Bool
186 flag n = toPermDefault False $ tagged n $ just True
187 shortOpt :: TagConstraint repr a => Char -> a -> repr (a->k) k -> Permutation repr k a
188 shortOpt n a = toPermDefault a . tagged (TagShort n)
189 longOpt :: TagConstraint repr a => Name -> a -> repr (a->k) k -> Permutation repr k a
190 longOpt n a = toPermDefault a . tagged (TagLong n)
193 type TagConstraint repr a = TagConstraint (UnTrans repr) a
196 CLI_Tag (UnTrans repr) =>
197 Tag -> repr f k -> repr f k
200 CLI_Tag (UnTrans repr) =>
202 tagged n = noTrans . tagged n . unTrans
203 endOpts = noTrans endOpts
205 -- * Class 'CLI_Response'
206 class CLI_Response repr where
207 type ResponseConstraint repr a :: Constraint
208 type ResponseArgs repr a :: * -- = (r:: *) | r -> a
209 type Response repr :: *
211 ResponseConstraint repr a =>
212 repr (ResponseArgs repr a)
215 type ResponseConstraint repr a = ResponseConstraint (UnTrans repr) a
216 type ResponseArgs repr a = ResponseArgs (UnTrans repr) a
217 type Response repr = Response (UnTrans repr)
221 CLI_Response (UnTrans repr) =>
222 ResponseConstraint (UnTrans repr) a =>
223 ResponseArgs repr a ~ ResponseArgs (UnTrans repr) a =>
224 Response repr ~ Response (UnTrans repr) =>
225 repr (ResponseArgs repr a)
227 response' = noTrans (response' @_ @a)
232 ResponseConstraint repr a =>
233 repr (ResponseArgs repr a)
235 response = response' @repr @a
236 {-# INLINE response #-}
238 -- * Class 'CLI_Help'
239 class CLI_Help repr where
240 type HelpConstraint repr d :: Constraint
241 help :: HelpConstraint repr d => d -> repr f k -> repr f k
243 program :: Name -> repr f k -> repr f k
244 rule :: Name -> repr f k -> repr f k
246 type HelpConstraint repr d = HelpConstraint (UnTrans repr) d
249 CLI_Help (UnTrans repr) =>
250 Name -> repr f k -> repr f k
253 CLI_Help (UnTrans repr) =>
254 Name -> repr f k -> repr f k
255 program n = noTrans . program n . unTrans
256 rule n = noTrans . rule n . unTrans
260 class Trans repr where
261 -- | The @(repr)@esentation that @(repr)@ 'Trans'forms.
262 type UnTrans repr :: * -> * -> *
263 -- | Lift the underlying @(repr)@esentation to @(repr)@.
264 -- Useful to define a combinator that does nothing in a 'Trans'formation.
265 noTrans :: UnTrans repr a b -> repr a b
266 -- | Unlift a @(repr)@esentation. Useful when a 'Trans'formation
267 -- combinator needs to access the 'UnTrans'formed @(repr)@esentation,
268 -- or at the end to get the underlying 'UnTrans'formed @(repr)@esentation
269 -- from the inferred @(repr)@ value (eg. in 'server').
270 unTrans :: repr a b -> UnTrans repr a b