module Idris.ProofSearch(trivial, proofSearch) where
import Idris.Core.Elaborate hiding (Tactic(..))
import Idris.Core.TT
import Idris.Core.Evaluate
import Idris.Core.CaseTree
import Idris.Core.Typecheck
import Idris.AbsSyntax
import Idris.Delaborate
import Idris.Error
import Control.Applicative ((<$>))
import Control.Monad
import Control.Monad.State.Strict
import Data.List
import Debug.Trace
trivial :: (PTerm -> ElabD ()) -> IState -> ElabD ()
trivial elab ist = try' (do elab (PRefl (fileFC "prf") Placeholder)
return ())
(do env <- get_env
g <- goal
tryAll env
return ()) True
where
tryAll [] = fail "No trivial solution"
tryAll ((x, b):xs)
= do
hs <- get_holes
g <- goal
if all (\n -> not (n `elem` hs)) (freeNames (binderTy b))
then try' (elab (PRef (fileFC "prf") x))
(tryAll xs) True
else tryAll xs
cantSolveGoal :: ElabD a
cantSolveGoal = do g <- goal
env <- get_env
lift $ tfail $
CantSolveGoal g (map (\(n,b) -> (n, binderTy b)) env)
proofSearch :: Bool ->
Bool ->
Bool ->
Bool ->
Int ->
(PTerm -> ElabD ()) -> Maybe Name -> Name -> [Name] ->
IState -> ElabD ()
proofSearch False fromProver ambigok deferonfail depth elab _ nroot [fn] ist
= do
let all_imps = lookupCtxtName fn (idris_implicits ist)
tryAllFns all_imps
where
tryAllFns [] | fromProver = cantSolveGoal
tryAllFns [] = do attack; defer [] nroot; solve
tryAllFns (f : fs) = try' (tryFn f) (tryAllFns fs) True
tryFn (f, args) = do let imps = map isImp args
ps <- get_probs
hs <- get_holes
args <- map snd <$> try' (apply (Var f) imps)
(match_apply (Var f) imps) True
ps' <- get_probs
hs' <- get_holes
ptm <- get_term
if fromProver then cantSolveGoal
else do
mapM_ (\ h -> do focus h
attack; defer [] nroot; solve)
(hs' \\ hs)
solve
isImp (PImp p _ _ _ _) = (True, p)
isImp arg = (True, priority arg)
proofSearch rec fromProver ambigok deferonfail maxDepth elab fn nroot hints ist
= do compute
ty <- goal
argsok <- conArgsOK ty
if ambigok || argsok then
case lookupCtxt nroot (idris_tyinfodata ist) of
[TISolution ts] -> findInferredTy ts
_ -> psRec rec maxDepth
else autoArg (sUN "auto")
where
findInferredTy (t : _) = elab (delab ist (toUN t))
conArgsOK ty
= let (f, as) = unApply ty in
case f of
P _ n _ -> case lookupCtxt n (idris_datatypes ist) of
[t] -> do rs <- mapM (conReady as) (con_names t)
return (and rs)
_ -> fail "Ambiguous name"
TType _ -> return True
_ -> fail "Not a data type"
conReady :: [Term] -> Name -> ElabD Bool
conReady as n
= case lookupTyExact n (tt_ctxt ist) of
Just ty -> do let (_, cs) = unApply (getRetTy ty)
hs <- get_holes
return $ and (map (notHole hs) (zip as cs))
Nothing -> fail "Can't happen"
notHole hs (P _ n _, c)
| (P _ cn _, _) <- unApply c,
n `elem` hs && isConName cn (tt_ctxt ist) = False
| Constant _ <- c = not (n `elem` hs)
notHole _ _ = True
toUN t@(P nt (MN i n) ty)
| ('_':xs) <- str n = t
| otherwise = P nt (UN n) ty
toUN (App f a) = App (toUN f) (toUN a)
toUN t = t
psRec _ 0 | fromProver = cantSolveGoal
psRec rec 0 = do attack; defer [] nroot; solve
psRec False d = tryCons d hints
psRec True d = do compute
try' (trivial elab ist)
(try' (try' (resolveByCon (d 1)) (resolveByLocals (d 1))
True)
(if fromProver
then fail "cantSolveGoal"
else do attack; defer [] nroot; solve) True) True
getFn d Nothing = []
getFn d (Just f) | d < maxDepth1 = [f]
| otherwise = []
resolveByCon d
= do t <- goal
let (f, _) = unApply t
case f of
P _ n _ -> case lookupCtxt n (idris_datatypes ist) of
[t] -> tryCons d (hints ++ con_names t ++
getFn d fn)
_ -> fail "Not a data type"
_ -> fail "Not a data type"
resolveByLocals d
= do env <- get_env
tryLocals d env
tryLocals d [] = fail "Locals failed"
tryLocals d ((x, t) : xs) = try' (tryLocal d x t) (tryLocals d xs) True
tryCons d [] = fail "Constructors failed"
tryCons d (c : cs) = try' (tryCon d c) (tryCons d cs) True
tryLocal d n t = do let a = getPArity (delab ist (binderTy t))
tryLocalArg d n a
tryLocalArg d n 0 = elab (PRef (fileFC "prf") n)
tryLocalArg d n i = simple_app False (tryLocalArg d n (i 1))
(psRec True d) "proof search local apply"
tryCon d n =
do ty <- goal
let imps = case lookupCtxtName n (idris_implicits ist) of
[] -> []
[args] -> map isImp (snd args)
_ -> fail "Ambiguous name"
ps <- get_probs
hs <- get_holes
args <- map snd <$> try' (apply (Var n) imps)
(match_apply (Var n) imps) True
ps' <- get_probs
hs' <- get_holes
when (length ps < length ps') $ fail "Can't apply constructor"
mapM_ (\ (_, h) -> do focus h
aty <- goal
psRec True d)
(filter (\ (x, y) -> not x) (zip (map fst imps) args))
solve
isImp (PImp p _ _ _ _) = (True, p)
isImp arg = (False, priority arg)