10 | import public Control.Monad.Either
11 | import public Control.Monad.State
12 | import public Data.Maybe
13 | import public Decidable.Equality
14 | import public Language.Reflection
16 | import public Deriving.Common
18 | %language ElabReflection
23 | (Prec -> ty -> String) ->
25 | fromShowPrec sp = MkShow (sp Open) sp
32 | data Error : Type where
33 | NotAShowable : Name -> Error
34 | UnsupportedType : TTImp -> Error
35 | NotAFiniteStructure : Error
36 | NotAnUnconstrainedValue : Count -> Error
38 | ConfusingReturnType : Error
40 | WhenCheckingConstructor : Name -> Error -> Error
41 | WhenCheckingArg : TTImp -> Error -> Error
45 | show = joinBy "\n" . go [<] where
47 | go : SnocList String -> Error -> List String
48 | go acc (NotAShowable nm) = acc <>> ["Couldn't find a `Show' instance for the type \{show nm}"]
49 | go acc (UnsupportedType s) = acc <>> ["Unsupported type \{show s}"]
50 | go acc NotAFiniteStructure = acc <>> ["Cannot show an infinite structure"]
51 | go acc (NotAnUnconstrainedValue rig) = acc <>> ["Cannot show a \{enunciate rig} value"]
52 | go acc InvalidGoal = acc <>> ["Expected a goal of the form `Show t`"]
53 | go acc ConfusingReturnType = acc <>> ["Confusing telescope"]
54 | go acc (WhenCheckingConstructor nm err) = go (acc :< "When checking constructor \{show nm}") err
55 | go acc (WhenCheckingArg s err) = go (acc :< "When checking argument of type \{show s}") err
57 | record Parameters where
58 | constructor MkParameters
59 | asShowables : List Nat
61 | initParameters : Parameters
62 | initParameters = MkParameters []
64 | paramConstraints : Parameters -> Nat -> Maybe TTImp
65 | paramConstraints params pos
66 | = IVar emptyFC `{Prelude.Show.Show
} <$ guard (pos `elem` params.asShowables)
71 | ShowN : TTImp -> Name -> TTImp
72 | ShowN ty nm = go (IVar emptyFC nm) ty Z where
74 | go : TTImp -> TTImp -> Nat -> TTImp
75 | go acc (IPi _ _ pinfo mn (IType _) ty) n
76 | = let var = MN "__param" (cast n) in
77 | IPi emptyFC M0 ImplicitArg (Just var) (Implicit emptyFC False)
78 | $
IPi emptyFC MW AutoImplicit Nothing (IApp emptyFC `(Show
) (IVar emptyFC var))
79 | $
go (TTImp.apply acc (toList (fromPiInfo emptyFC pinfo mn (IVar emptyFC var)))) ty (S n)
80 | go acc (IPi _ _ pinfo mn _ ty) n
81 | = let var = MN "__param" (cast n) in
82 | IPi emptyFC M0 ImplicitArg (Just var) (Implicit emptyFC False)
83 | $
go (TTImp.apply acc (toList (fromPiInfo emptyFC pinfo mn (IVar emptyFC var)))) ty (S n)
84 | go acc _ _ = IApp emptyFC `(Show
) acc
92 | data IsShowable : (t : Name) -> (ty : TTImp) -> Type
93 | data IsShowableArgs : (t : Name) -> (tconty : TTImp) -> (ty : List (Argument TTImp)) -> Type
95 | data IsShowable : (t : Name) -> (ty : TTImp) -> Type where
97 | ISDelayed : IsShowable t ty -> IsShowable t (IDelayed fc LLazy ty)
99 | ISRec : (0 _ : IsAppView (_, t) _ ty) -> IsShowable t ty
102 | ISShowN : (0 _ : IsAppView (_, tcon) args ty) ->
103 | HasType tcon tconty ->
104 | IsProvable (ShowN tconty tcon) ->
105 | IsShowableArgs t tconty (args <>> []) -> IsShowable t ty
107 | ISParam : IsShowable t ty
109 | ISPrim : (ty : PrimType) -> IsShowable t (IPrimVal fc (PrT ty))
111 | data IsShowableArgs : (t : Name) -> (tconty : TTImp) -> (ty : List (Argument TTImp)) -> Type where
112 | Done : IsShowableArgs t tconty []
113 | Step : IsShowable t (unArg arg) -> IsShowableArgs t ty args ->
114 | IsShowableArgs t (IPi fc1 r ExplicitArg mn (IType fc2) ty) (arg :: args)
115 | Drop : (forall fc. Not (dom === IType fc)) -> IsShowableArgs t ty args ->
116 | IsShowableArgs t (IPi fc1 r ExplicitArg mn dom ty) (arg :: args)
117 | Skip : Not (pinfo === ExplicitArg) -> IsShowableArgs t ty args ->
118 | IsShowableArgs t (IPi fc1 r pinfo mn dom ty) args
120 | parameters (fc : FC) (mutualWith : List Name)
122 | isRecs : IsShowableArgs t ty ts -> Bool
123 | isRec : IsShowable t ts -> Bool
125 | isRecs Done = False
126 | isRecs (Step x xs) = isRec x || isRecs xs
127 | isRecs (Drop f xs) = isRecs xs
128 | isRecs (Skip f xs) = isRecs xs
130 | isRec (ISDelayed x) = isRec x
131 | isRec (ISRec _) = True
132 | isRec (ISShowN _ _ _ xs) = isRecs xs
133 | isRec ISParam = False
134 | isRec (ISPrim _) = False
136 | showPrecFun : {ty : _} -> IsShowable t ty -> TTImp -> TTImp
137 | showPrecFun (ISDelayed p) t = showPrecFun p (IForce (getFC t) t)
138 | showPrecFun (ISRec _) t = IApp emptyFC `(assert_total
) (IApp emptyFC `(showArg
) t)
139 | showPrecFun {ty} (ISShowN _ _ _ as) t
140 | = let isMutual = fromMaybe False (appView ty >>= \ v => pure (snd v.head `elem` mutualWith)) in
141 | ifThenElse (isMutual || isRecs as) (IApp emptyFC `(assert_total
)) id
142 | $
IApp emptyFC `(showArg
) t
143 | showPrecFun ISParam t = IApp emptyFC `(showArg
) t
144 | showPrecFun (ISPrim pty) t = IApp emptyFC `(showArg
) t
147 | {0 m : Type -> Type}
148 | {auto elab : Elaboration m}
149 | {auto error : MonadError Error m}
150 | {auto cs : MonadState Parameters m}
152 | (ps : List (Name, Nat))
156 | typeView : (ty : TTImp) -> m (IsShowable t ty)
157 | typeViews : (tconty : TTImp) -> (tys : List (Argument TTImp)) ->
158 | m (IsShowableArgs t tconty tys)
160 | typeView (IDelayed _ lz ty) = case lz of
161 | LLazy => ISDelayed <$> typeView ty
162 | _ => throwError NotAFiniteStructure
163 | typeView (IPrimVal _ (PrT ty)) = pure (ISPrim ty)
165 | let Just (MkAppView (_, hd) ts prf) = appView ty
166 | | _ => throwError (UnsupportedType ty)
167 | let No _ = decEq hd t
168 | | Yes Refl => pure (ISRec prf)
169 | Just (
hdty ** hT)
<- hasType hd
170 | | _ => case lookup hd ps <* guard (null ts) of
173 | ns <- gets asShowables
174 | let ns = ifThenElse (n `elem` ns) ns (n :: ns)
175 | modify { asShowables := ns }
177 | logMsg "derive.show.assumption" 10 $
178 | "I am assuming that the parameter \{show hd} can be shown"
180 | _ => throwError (UnsupportedType ty)
181 | Just iP <- isProvable (ShowN hdty hd)
182 | | _ => throwError (NotAShowable hd)
183 | ISShowN prf hT iP <$> typeViews hdty (ts <>> [])
185 | typeViews _ [] = pure Done
186 | typeViews (IPi _ _ ExplicitArg _ (IType fc) ty) (t :: ts)
187 | = Step <$> assert_total (typeView (unArg t)) <*> typeViews ty ts
188 | typeViews (IPi _ _ ExplicitArg _ dom ty) (t :: ts)
189 | = Drop (\ x => believe_me x) <$> typeViews ty ts
190 | typeViews (IPi _ _ _ _ _ ty) ts
191 | = Skip (\ x => believe_me x) <$> typeViews ty ts
192 | typeViews ty ts = throwError (UnsupportedType ty)
196 | derive' : (Elaboration m, MonadError Error m) =>
197 | {default Private vis : Visibility} ->
198 | {default Total treq : TotalReq} ->
199 | {default [] mutualWith : List Name} ->
204 | mutualWith <- map concat $
for mutualWith $
\ nm => do
206 | pure (fst <$> ntys)
209 | Just (IApp _ (IVar _ showable) t) <- goal
210 | | _ => throwError InvalidGoal
211 | when (`{Prelude.Show.Show
} /= showable) $
212 | logMsg "derive.show" 1 "Expected to derive Show but got \{show showable}"
215 | logMsg "derive.show" 1 "Deriving Show for \{showPrec App $ mapTTImp cleanup t}"
216 | MkIsType f params cs <- isType t
217 | logMsg "derive.show.constructors" 1 $
218 | joinBy "\n" $
"" :: map (\ (n, ty) => " \{showPrefix True $ dropNS n} : \{show $ mapTTImp cleanup ty}") cs
222 | let un = UN . Basic
223 | let showName = un ("showPrec" ++ show (dropNS f))
224 | let precName = un "d"
225 | let prec = IVar fc precName
226 | (ns, cls) <- runStateT {m = m} initParameters $
for cs $
\ (cName, ty) =>
227 | withError (WhenCheckingConstructor cName) $
do
229 | let Just (MkConstructorView paraz args) = constructorView ty
230 | | _ => throwError ConfusingReturnType
231 | logMsg "derive.show.clauses" 10 $
232 | "\{showPrefix True (dropNS cName)} (\{joinBy ", " (map (showPrec Dollar . mapTTImp cleanup . unArg . snd) args)})"
234 | let args = mapMaybe (bitraverse pure (map snd . isExplicit)) args
236 | let (_ :: _) = args
237 | | [] => pure $
PatClause fc
238 | (apply fc (IVar fc showName) [ prec, IVar fc cName])
239 | (IPrimVal fc (Str (showPrefix True (dropNS cName))))
241 | let vars = zipWith (const . IVar fc . un . ("x" ++) . show . (`minus` 1)) [1..length args] args
242 | recs <- for (zip vars args) $
\ (v, (rig, ty)) => do
245 | | _ => throwError (NotAnUnconstrainedValue rig)
248 | ty <- try (check {expected=Type} ty >>= \x => quote x) (pure ty)
249 | res <- withError (WhenCheckingArg (mapTTImp cleanup ty)) $
do
250 | typeView f (paraz <>> []) ty
251 | pure $
Just (showPrecFun fc mutualWith res v)
253 | let args = catMaybes recs
254 | let asList = foldr (\ a, as => apply fc (IVar fc `{Prelude.(::)
}) [a,as]) `(Prelude.Nil
)
255 | pure $
PatClause fc
256 | (apply fc (IVar fc showName) [ prec, apply fc (IVar fc cName) vars])
257 | (apply fc (IVar fc (un "showCon"))
259 | , IPrimVal fc (Str (showPrefix True (dropNS cName)))
262 | _ => IApp fc (IVar fc (un "concat")) (asList args)
266 | let ty = MkTy fc (NoFC showName) $
withParams fc (paramConstraints ns) params
267 | $
`(Prec
-> ~(t) -> String)
268 | logMsg "derive.show.clauses" 1 $
269 | joinBy "\n" ("" :: (" " ++ show (mapITy cleanup ty))
270 | :: map ((" " ++) . showClause InDecl . mapClause cleanup) cls)
274 | [ IClaim (MkFCVal fc (MkIClaimData MW vis [Totality treq] ty))
275 | , IDef fc showName cls
276 | ] `(fromShowPrec
~(IVar fc showName))
286 | derive : {default Private vis : Visibility} ->
287 | {default Total treq : TotalReq} ->
288 | {default [] mutualWith : List Name} ->
291 | res <- runEitherT {e = Error, m = Elab} (derive' {vis, treq, mutualWith})
293 | Left err => fail (show err)
294 | Right prf => pure prf