I am having trouble convincing Idris to verify that my function is complete. Here is a simple sample problem that I am facing. Let's say we have a very simple type of expression of the following form:
data SimpleType = Prop | Fn SimpleType SimpleType
data Expr : SimpleType -> Type where
Var : String -> Expr type
Lam : String -> Expr rng -> Expr (Fn dom rng)
App : Expr (Fn dom rng) -> Expr dom -> Expr rng
I would like to write a function
total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
for which you need an DecEqinstance for SimpleType, but nothing unusual. The problem is how to convince the type check that the function is complete. For example, consider implementing it subas follows:
total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub name repl (App l r) = App (substitute name repl l) (substitute name repl r)
sub _ _ expr = expr
(This is incorrect, but a great place to run.) This gives an error:
Main.sub is possibly not total due to: repl
At first glance, it seems that Idris may have problems verifying that l and r are structurally smaller than (App lr). Perhaps the following will work?
total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub name repl expr@(App l r) = App
(sub name repl (assert_smaller expr l))
(sub name repl (assert_smaller expr r))
sub _ _ expr = expr
Nope!
Main.sub is possibly not total due to: repl
, , , :
total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub _ _ expr = expr
!
total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub _ repl expr = expr
, , repl . - , ?