6

I've been having trouble convincing the Idris totality checker that my function is total. Here's a simple example version of the problem I'm running into. Say we have a very simple expression type 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'd like to write the function

total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b

which will require a DecEq instance for SimpleType but nothing too fancy. The problem is how to convince the type checker that the function is total. For instance, consider implementing sub as 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

(which is incorrect, but a fine place to start.) This yields the error:

Main.sub is possibly not total due to: repl

At first glance, it seems that perhaps Idris is having trouble verifying that l and r are structurally smaller than (App l r). 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

In fact, on further investigation, it is revealed that, while this program compiles:

total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub _ _ expr = expr

This one does not!

total sub : {a, b : SimpleType} -> String -> Expr a -> Expr b -> Expr b
sub _ repl expr = expr

And now I am at a loss as to how to convince Idris that, in this final example, repl really isn't going to interfere with totality. Anyone know how to make this work?

So8res
  • 9,856
  • 9
  • 56
  • 86
  • 2
    It's simply a bug. There quite a few of them in Idris currently. If you're using Idris for formalization, you should instead consider Agda which is far more mature in this regard, and supports basically everything that can be written in Idris, with moderate syntactic differences. – András Kovács Mar 05 '16 at 23:51
  • 1
    This does indeed appear to be a silly error in the totality checker. It thinks you're referring to 'repl' from the library, which you're obviously not... I'll take a quick look at this. The totality checker hasn't had much attention, unfortunately. Unlike the Agda one which has had plenty of effort put into it by people who have lots of experience in writing termination checkers, the Idris checker is the work of a few afternoons by me, so it isn't especially mature. It does try to err on the side of caution, though. – Edwin Brady Mar 09 '16 at 08:52

1 Answers1

8

This turns out to be an error in the totality checker, where it thinks the 'repl' you're referring to on the left hand side is the one defined in the library for making simple interactive loops. It obviously isn't - it's just a mistake in the name lookup - and it's trivial to fix this.

This is fixed in the git master and will therefore be fixed in the next release. In the meantime, using a different name than 'repl' will work (I realise this is a bit annoying, but there you go...)

Edwin Brady
  • 4,546
  • 1
  • 22
  • 14