Source code on Github{-# OPTIONS -v try:100 #-}
module Tactic.Try where
open import Meta.Prelude
open import Data.List
open import Reflection hiding (_>>=_; _>>_; _≟_)
open import Reflection.Syntax
open import Reflection.Utils
open import Reflection.Utils.Debug
open import Reflection.Utils.TCM
open import Relation.Nullary
open import Class.DecEq
open import Class.Functor
open import Class.Monad
open import Class.Semigroup
open import Class.Show
open Debug ("try" , 100)
_∙_ : Term → Args Term → TC Term
t ∙ [] = return t
t ∙ es′@(_ ∷ _) with t
... | var x es = return $ var x (es′ ++ es)
... | con c es = return $ con c (es′ ++ es)
... | def f es = return $ def f (es′ ++ es)
... | pat-lam cs es = return $ pat-lam cs (es′ ++ es)
... | meta x es = return $ meta x (es′ ++ es)
... | e = error $ "cannot apply arguments to " ◇ show t
private module _ {ℓ ℓ′} {A : Set ℓ} {B : Set ℓ′} ⦃ _ : DecEq A ⦄ where
import Data.List.Membership.DecPropositional {A = A} _≟_ as DL
nubBy : (B → A) → List B → List B
nubBy f [] = []
nubBy f (x ∷ xs) with f x DL.∈? map f xs
... | yes _ = nubBy f xs
... | no _ = x ∷ nubBy f xs
nodup : List Term → List Term
nodup = nubBy show
private
variable
A B : Set
doN : {{_ : DecEq A}} → ℕ → (A → TC A) → (A → TC A)
doN 0 _ x = return x
doN (suc n) f x = do
y ← f x
if (y ≠ x) then doN n f y else return x
ifM_then_else_ : TC Bool → TC A → TC A → TC A
ifM mb then k else k′ = do
b ← mb
if b then k else k′
caseM_of_ : TC A → (A → TC B) → TC B
caseM k of f = do
x ← k
case x of f
infixl 0 _∣_
_∣_ : TC A → TC A → TC A
f ∣ g = catchTC f g
amb : List (TC A) → TC A
amb = foldr _∣_ (error "∅")
infix 4 _≔_
_≔_ : Term → List Term → TC ⊤
t ≔ es = amb $ map (unify t) es
purely : TC A → TC A
purely k = runSpeculative (fmap (_, false) k)
record Subterms (A : Set) : Set where
field
subterms : A → List Term
open Subterms {{...}}
instance
STerm : Subterms Term
STerm .subterms t = t ∷ (case t of λ where
(var _ []) → []
(var x (arg _ e ∷ as)) → subterms e ++ subterms (var x as)
(con _ []) → []
(con c (arg _ e ∷ as)) → subterms e ++ subterms (con c as)
(def _ []) → []
(def f (arg _ e ∷ as)) → subterms e ++ subterms (def f as)
(pi (arg _ ty) (abs _ e)) → subterms ty ++ subterms e
_ → [])
SArg : {{_ : Subterms A}} → Subterms (Arg A)
SArg .subterms = subterms ∘ unArg
SAbs : {{_ : Subterms A}} → Subterms (Abs A)
SAbs .subterms = subterms ∘ unAbs
SList : {{_ : Subterms A}} → Subterms (List A)
SList .subterms = concatMap subterms
fits? : Type → Term → TC Bool
fits? ty e = inferType e >>= compatible? ty
apply? : Type → Type → TC (Maybe (Args Type))
apply? ty ty₀ = go ty []
where
go : Type → Args Type → TC (Maybe (Args Type))
go ty as =
ifM compatible? ty ty₀ then
return (just as)
else (case ty of λ where
(Π[ _ ∶ a ] ty′) → go ty′ (as ++ [ a ])
_ → return nothing)
{-# TERMINATING #-}
allCandidates : List Term → Type → TC (List Term)
tryOut : List Term → Term × Type → TC (List Term)
allCandidates db ty = fmap concat $ mapM go db
where
go : Term → TC (List Term)
go e = do
eTy ← inferType e
caseM apply? eTy ty of λ where
nothing → return []
(just tys) → tryOut db (e , eTy)
tryOut db (f , fTy) = purely (do
cs ← forM (argTys fTy) λ where
(arg i ty) → do
cs′ ← allCandidates db ty
return $ map (arg i) cs′
mapM (f ∙_) (combinations cs)) ∣ return db
where
combinations : List (List A) → List (List A)
combinations [] = [ [] ]
combinations (xs ∷ xss) = concatMap (λ x → map (x ∷_) xss′) xs
where xss′ = combinations xss
prints : {{_ : Show A}} → String → List A → TC ⊤
prints pre xs = print (pre ◇ " {") >> go xs
where
go : {{_ : Show A}} → List A → TC ⊤
go [] = print "}"
go (x ∷ xs) = print ("\t" ◇ show x) >> go xs
mapArgs : (Args Term → Args Term) → Term → Term
mapArgs f t₀ with t₀
... | var x as = var x (f as)
... | con x as = con x (f as)
... | def x as = def x (f as)
... | lam x (abs s t) = lam x (abs s $ mapArgs f t)
... | _ = t₀
countLambdas : Term → ℕ
countLambdas (lam _ (abs _ t)) = suc $ countLambdas t
countLambdas _ = 0
η-reduce : Term → Term
η-reduce t = t
viewTerm : Term → TC (Term × Type)
viewTerm t = do
fmap (t ,_) (inferType t)
tryWith : List Term → Term → Term → TC ⊤
tryWith userDB f₀ hole₀ = do
print "---------------------------------"
(hole , holeTy) ← viewTerm hole₀
print $ "hole : " ◇ show holeTy
(f , fTy) ← viewTerm f₀
print $ show f ◇ " : " ◇ show fTy
ctx ← getContext
printCurrentContext
let
db : List Term
db = nodup
$ map ♯ (upTo $ length ctx)
++ subterms holeTy
++ subterms (map proj₂ ctx)
++ userDB
++ [ unknown ]
prints "db" db
es ← tryOut db (f , fTy)
prints "es" es
hole ≔ es
macro
try_∶-_ : Term → List Term → Term → TC ⊤
try t ∶- userDB = tryWith userDB t
try : Term → Term → TC ⊤
try = tryWith []
private
test₀ : (Bool → ℕ) → Bool → ℕ
test₀ f b = try f
_ : test₀ (if_then 1 else 0) true ≡ 1
_ = refl
test : (Bool → ℕ) → ℕ
test f = try f ∶- ( quote true ◆
∷ quote Bool ∙
∷ quote ℕ ∙
∷ quoteTerm (1 + 1)
∷ [])
_ : test (if_then 1 else 0) ≡ 1
_ = refl
test′ : ⊤ → (Bool → ℕ) → (⊤ → Bool) → ℕ
test′ t f g = try f
_ : test′ tt (if_then 1 else 9) (λ tt → true) ≡ 1
_ = refl
test₂ : (ℕ → Bool) → ℕ → ℕ → Bool
test₂ f n m = try f
_ : test₂ (_== 42) 10 42 ≡ true
_ = refl