on master help sign in
Merge pull request #2749 from david-christiansen/pruviloj

Pruviloj and Elab updates

commit7b30b6d0bc37783c981a79197084df2a58894d1c authorDavid Christiansen <david@davidchristiansen.dk> dateSun 25 Oct 2015, 17:25 (11 years ago) parent467490b58ddcd0
8 files changed+242−24
libs/prelude/Language/Reflection/Elab.idr+2−2 libs/pruviloj/Pruviloj/Derive/DecEq.idr+198 libs/pruviloj/Pruviloj/Derive/Eliminators.idr+4−10 libs/pruviloj/Pruviloj/Internals.idr+3−2 libs/pruviloj/pruviloj.ipkg+1 src/Idris/Elab/Term.hs+2−10 test/meta002/Deriving.idr+31 test/meta002/run+1
libs/prelude/Language/Reflection/Elab.idr+2−2
@@ -113,7 +113,7 @@ data Elab : Type -> Type where
113113 Prim__Env : Elab (List (TTName, Binder TT))
114114 Prim__Goal : Elab (TTName, TT)
115115 Prim__Holes : Elab (List TTName)
116− Prim__Guess : Elab (Maybe TT)
116+ Prim__Guess : Elab TT
117117 Prim__LookupTy : TTName -> Elab (List (TTName, NameType, TT))
118118 Prim__LookupDatatype : TTName -> Elab (List Datatype)
119119 Prim__LookupArgs : TTName -> Elab (List (TTName, List FunArg, Raw))
@@ -202,7 +202,7 @@ namespace Tactics
202202 getHoles = Prim__Holes
203203
204204 ||| If the current hole contains a guess, return it. Otherwise, fail.
205− getGuess : Elab (Maybe TT)
205+ getGuess : Elab TT
206206 getGuess = Prim__Guess
207207
208208 ||| Look up the types of every overloading of a name.
libs/pruviloj/Pruviloj/Derive/DecEq.idrnew file+198
@@ -0,0 +1,198 @@
1+||| Derive implementations of decidable equality.
2+module Pruviloj.Derive.DecEq
3+
4+import Data.Fin
5+import Data.Vect
6+
7+import Language.Reflection.Utils
8+
9+import Pruviloj.Core
10+
11+import Pruviloj.Renamers
12+import Pruviloj.Internals
13+
14+import Pruviloj.Derive.Eliminators
15+
16+import Pruviloj.Disjoint
17+import Pruviloj.Induction
18+import Pruviloj.Injective
19+
20+%default total
21+%access private
22+
23+
24+covering
25+noCase : TTName -> Elab ()
26+noCase contra =
27+ do [_, nope] <- apply (Var `{No}) [True, False]
28+ | _ => fail [TextPart "Bad holes from", NamePart `{Tactics.apply}]
29+ solve
30+ focus nope
31+
32+ -- Construct a lambda binding an assumption from which we can
33+ -- derive the contradiction
34+ h <- gensym "h"
35+ inj <- gensym "inj"
36+ attack
37+ intro h
38+ injective (Var h) inj
39+ unproduct (Var inj)
40+ ignore $ refine (Var contra) `andThen` hypothesis
41+ solve -- attack
42+
43+partial -- TODO make covering/total
44+matchCase : List Raw -> Elab ()
45+matchCase [] = search
46+matchCase (tm :: tms) =
47+ do hs <- induction tm
48+ y <- unsafeNth 0 hs
49+ n <- unsafeNth 1 hs
50+
51+ focus n; compute
52+ contra <- gensym "contra"
53+ attack; intro contra
54+ noCase contra; solve
55+
56+ focus y; compute
57+ prf <- gensym "prf"
58+ attack; intro prf
59+ rewriteWith (Var prf)
60+ matchCase tms
61+ solve
62+
63+spanM : (Monad m) => (a -> m Bool) -> List a -> m (List a, List a)
64+spanM p [] = pure ([], [])
65+spanM p (x::xs) =
66+ if !(p x)
67+ then do (yes, no) <- spanM p xs
68+ pure (x :: yes, no)
69+ else pure ([], x::xs)
70+
71+partitionM : Monad m => (a -> m Bool) -> List a -> m (List a, List a)
72+partitionM p [] = pure ([], [])
73+partitionM p (x :: xs) =
74+ do (y, n) <- partitionM p xs
75+ if !(p x) then pure (x :: y, n) else pure (y, x :: n)
76+
77+perhaps : (Alternative f) => (f a) -> (f (Maybe a))
78+perhaps x = (Just <$> x) <|> pure Nothing
79+
80+headIs : Raw -> TTName -> Bool
81+headIs tm n = maybe False (==n) (headName tm)
82+
83+partial
84+mkRhs : (fn, fam : TTName) -> Nat -> Elab ()
85+mkRhs fn fam k =
86+ case snd !getGoal of
87+ `(Dec ((=) {A=~A} {B=~_} ~x ~y)) =>
88+ let (c1, args1) = unApply x
89+ (c2, args2) = unApply y
90+ in if c1 /= c2
91+ then do (h :: _) <- refine (Var `{No})
92+ | _ => empty
93+ focus h
94+ disjoint
95+ else do let toMakeEqual = List.filter (uncurry (/=)) (zip args1 args2)
96+ tms <- for {b=Raw} toMakeEqual $ \(tm1, tm2) =>
97+ do env <- getEnv
98+ (tm1', ty1') <- forget tm1 >>= check env
99+ (tm2', ty2') <- forget tm2 >>= check env
100+ -- assume they have the same type here -
101+ -- reasonable due to same constructor, but
102+ -- this means order is important when
103+ -- traversing
104+ eq <- gensym "eq"
105+ rTy <- forget ty1'
106+ rTm1 <- forget tm1'
107+ rTm2 <- forget tm2'
108+ remember eq `(Dec ((=) {A=~rTy} {B=~rTy} ~rTm1 ~rTm2))
109+ simple $
110+ if headIs rTy fam
111+ then do (a2::a1::hs) <- reverse <$> apply (Var fn) (replicate k True ++ [False, False])
112+ solve
113+ focus a1; fill rTm1; solve
114+ focus a2; fill rTm2; solve
115+ for_ hs $ \h => inHole h (resolveTC fn)
116+ else do [_, dH, a1, a2] <- apply (Var `{decEq}) [True, False, False, False]
117+ solve
118+ focus a1; fill rTm1; solve
119+ focus a2; fill rTm2; solve
120+ focus dH; resolveTC fn
121+ return (Var eq)
122+ matchCase tms
123+ _ => fail [TextPart "Inapplicable"]
124+
125+||| Attempt to derive the body of an implementation of decidable
126+||| equality based on an existing type signature.
127+|||
128+||| The function signature must provide enough information for the
129+||| deriving to occur. It must consist of zero or more non-constraint
130+||| arguments followed by zero or more constraint arguments, followed
131+||| by the two values to compare. The constraint arguments must
132+||| provide sufficient instances of `DecEq` to decide the equality of
133+||| each constructor field. The final two arguments to the function
134+||| declaration must be the two values that will be compared for
135+||| equality.
136+|||
137+||| @ fn the name of the function whose type has been declared
138+abstract partial -- because of mkRhs
139+deriveDecEq : (fn : TTName) -> Elab ()
140+deriveDecEq fn =
141+ do (_, Ref, sig') <- lookupTyExact fn
142+ sig <- forget sig'
143+ (args, `(Dec ((=) {A=~A} {B=~_} ~(Var x) ~(Var y)))) <- stealBindings sig noRenames
144+ | other => fail [ TextPart "Return type"
145+ , RawPart (snd other)
146+ , TextPart "isn't decidable equality"
147+ ]
148+
149+ datatype <- maybe (fail [ RawPart A
150+ , TextPart "is not an application of a TC"
151+ ])
152+ lookupDatatypeExact
153+ (headName A)
154+
155+ -- the signature must be like this:
156+ -- 1. a collection of variable bindings (will be implicit)
157+ -- 2. a collection of constraints
158+ -- 3. the arguments x and y from the return type
159+ (bindings, constrs, arg1, arg2) <-
160+ the (Elab (List (TTName, Binder Raw),
161+ List (TTName, Binder Raw),
162+ (TTName, Binder Raw),
163+ (TTName, Binder Raw))) $
164+ case reverse args of
165+ [] => fail [TextPart "Invalid signature"]
166+ [_] => fail [TextPart "Invalid signaure"]
167+ (a2 :: a1 :: rest) =>
168+ do (constrs, bindings) <- partitionM (\x => isConstr (binderTy (snd x)))
169+ (reverse rest)
170+ return (bindings, constrs, a1, a2)
171+ let todo = [(c1, c2) | c1 <- constructors datatype
172+ , c2 <- constructors datatype]
173+ clauses <- for todo
174+ (uncurry $ mkCase (length bindings + length constrs)
175+ (name datatype))
176+ defineFunction $ DefineFun fn (catMaybes clauses)
177+ skip
178+
179+ where
180+ isConstr : Raw -> Elab Bool
181+ isConstr tm = case headName tm of
182+ Just n => isTCName n
183+ Nothing => return False
184+
185+ partial -- mkRhs
186+ mkCase : Nat -> TTName -> (x, y : (TTName, List CtorArg, Raw)) -> Elab (Maybe FunClause)
187+ mkCase k fam (cn1, args1, _) (cn2, args2, _) =
188+ perhaps $ elabPatternClause
189+ (do (h2 :: h1 :: _) <- reverse <$>
190+ apply (Var fn) (replicate k True ++ [False, False])
191+ solve
192+ focus h1
193+ apply (Var cn1) (replicate (length args1) True)
194+ solve
195+ focus h2
196+ apply (Var cn2) (replicate (length args2) True)
197+ solve)
198+ (mkRhs fn fam k)
libs/pruviloj/Pruviloj/Derive/Eliminators.idr+4−10
@@ -18,7 +18,7 @@ bindParams info = traverse_ (uncurry forall) (getParams info)
1818||| rewrite an application of something to their designated global
1919||| names
2020bindIndices : TyConInfo -> Elab Renamer
21−bindIndices info = bind' (getIndices info) (const Nothing)
21+bindIndices info = bind' (getIndices info) noRenames
2222 where bind' : List (TTName, Raw) -> Renamer -> Elab Renamer
2323 bind' [] ren = return ren
2424 bind' ((n, t) :: ixs) ren = do n' <- nameFrom n
@@ -54,7 +54,7 @@ headsMatch x y =
5454||| Make an induction hypothesis if one is called for
5555mkIh : TyConInfo -> (motiveName : TTName) -> (recArg : TTName) -> (argty, fam : Raw) -> Elab ()
5656mkIh info motiveName recArg argty fam =
57− case !(stealBindings argty (const Nothing)) of
57+ case !(stealBindings argty noRenames) of
5858 (argArgs, argRes) =>
5959 if headsMatch argRes fam
6060 then do ih <- gensym "ih"
@@ -96,19 +96,13 @@ elabMethodTy info motiveName (CtorField arg :: args) res ctorApp =
9696 solve
9797
9898
99−
100−elabMethod : TyConInfo -> (motiveName, ctorN : TTName) -> List CtorArg -> Raw -> Elab ()
101−elabMethod info motiveName ctorN ctorArgs resTy =
102− do elabMethodTy info motiveName ctorArgs resTy (Var ctorN)
103−
104−
10599||| Bind a method for a constructor
106100bindMethod : TyConInfo -> (motiveName, cn : TTName) -> List CtorArg -> Raw -> Elab ()
107101bindMethod info motiveName cn cargs cty =
108102 do n <- nameFrom cn
109103 h <- newHole "methTy" `(Type)
110104 forall n (Var h)
111− focus h; elabMethod info motiveName cn cargs cty
105+ focus h; elabMethodTy info motiveName cargs cty (Var cn)
112106
113107getElimTy : TyConInfo -> List (TTName, List CtorArg, Raw) -> Elab Raw
114108getElimTy info ctors =
@@ -197,7 +191,7 @@ getElimClause info elimn methCount (cn, args, resTy) whichCon =
197191 CtorField arg =>
198192 do let n = name arg
199193 let t = type arg
200− (argArgs, argRes) <- stealBindings t (const Nothing)
194+ (argArgs, argRes) <- stealBindings t noRenames
201195 if headsMatch argRes (result info) --recursive
202196 then return [ NormalArgument n
203197 , IHArgument n
libs/pruviloj/Pruviloj/Internals.idr+3−2
@@ -112,8 +112,9 @@ elabPatternClause lhs rhs =
112112 focus patH
113113 lhs
114114 -- Convert all remaining holes to pattern variables
115− traverse_ {b=()} (\h => focus h *> patvar h) !getHoles
116− (pvars, `(MkInfer ~rhsTy ~lhsTm)) <- extractBinders <$> (forget pat)
115+ for_ {b=()} !getHoles $ \h =>
116+ do focus h; patvar h
117+ (pvars, `(MkInfer ~rhsTy ~lhsTm)) <- extractBinders <$> forget pat
117118 | fail [TextPart "Couldn't infer type of left-hand pattern"]
118119 rhsTm <- runElab (bindPatTys pvars rhsTy) $
119120 do -- Introduce all the pattern variables from the LHS
libs/pruviloj/pruviloj.ipkg+1
@@ -3,6 +3,7 @@ package pruviloj
33opts = "--nobasepkgs -i ../prelude -i ../base"
44modules = Pruviloj
55 , Pruviloj.Core
6+ , Pruviloj.Derive.DecEq
67 , Pruviloj.Derive.Eliminators
78 , Pruviloj.Disjoint
89 , Pruviloj.Induction
src/Idris/Elab/Term.hs+2−10
@@ -1831,16 +1831,8 @@ runElabAction ist fc env tm ns = do tm' <- eval tm
18311831 fmap fst . checkClosed $
18321832 mkList (Var $ reflm "TTName") (map reflectName hs)
18331833 | n == tacN "Prim__Guess", [] <- args
1834− = do ok <- is_guess
1835− if ok
1836− then do guess <- fmap forget get_guess
1837− fmap fst . get_type_val $
1838− RApp (RApp (Var (sNS (sUN "Just") ["Maybe", "Prelude"]))
1839− (Var (reflm "TT")))
1840− guess
1841− else fmap fst . checkClosed $
1842− RApp (Var (sNS (sUN "Nothing") ["Maybe", "Prelude"]))
1843− (Var (reflm "TT"))
1834+ = do g <- get_guess
1835+ fmap fst . checkClosed $ reflect g
18441836 | n == tacN "Prim__LookupTy", [n] <- args
18451837 = do n' <- reifyTTName n
18461838 ctxt <- get_context
test/meta002/Deriving.idrnew file+31
@@ -0,0 +1,31 @@
1+||| Test some deriving features
2+module Deriving
3+
4+import Pruviloj
5+import Pruviloj.Derive.DecEq
6+
7+data Vect : Nat -> Type -> Type where
8+ Nil : Vect Z a
9+ (::) : a -> Vect n a -> Vect (S n) a
10+
11+total
12+decVectEq : DecEq a => (xs, ys : Vect n a) -> Dec (xs = ys)
13+%runElab (deriveDecEq `{decVectEq})
14+
15+instance DecEq a => DecEq (Vect n a) where
16+ decEq xs ys = decVectEq xs ys
17+
18+forgetProof : Dec a -> Bool
19+forgetProof (Yes _) = True
20+forgetProof (No _) = False
21+
22+test1 : (xs, ys : Vect n Nat) -> Bool
23+test1 xs ys with (decEq xs ys)
24+ test1 xs xs | Yes Refl = True
25+ test1 xs ys | No _ = False
26+
27+
28+
29+-- Local Variables:
30+-- idris-load-packages: ("pruviloj")
31+-- End:
test/meta002/run+1
@@ -1,4 +1,5 @@
11#!/usr/bin/env bash
22idris $@ -p pruviloj --nocolour --check --consolewidth 70 Tacs.idr
33idris $@ -p pruviloj --nocolour --check --consolewidth 70 AgdaStyleReflection.idr
4+idris $@ -p pruviloj --nocolour --check --consolewidth 70 Deriving.idr
45rm -f *.ibc