3

I am experimenting with Idris a lot lately and came up with the following "type level definition of a set":

mutual
  data Set : Type -> Type where
    Empty : Set a
    Insert : (x : a) -> (xs : Set a) -> Not (Elem x xs) -> Set a

  data Elem : (x : a) -> Set a -> Type where
    Here : Elem x (Insert x xs p)
    There : Elem x xs -> Elem x (Insert y xs p)

So a set is either empty or it consists of a set and an additional element that is proven not to be in that set already.

When I totality check this, I get the error

[...] is not strictly positive

for Insert, Here and There. I have been searching the documentation for terms like "strictly positive" and the totality checker in general, but I cannot figure out why this case in particular is not total (or strictly positive). Can somebody explain this?

The natural next question then is of course how to "fix" it. Can I somehow change the definition, keeping its semantics, so that it totality checks?

Since I don't really need the definition to look like this (it is only an experiment after all) it would also be interesting to know whether there is another, somehow more idiomatic way to represent Sets at the type level that is total.

Julian Kniephoff
  • 1,003
  • 7
  • 14

1 Answers1

1

This SO post explains what strictly positive types are and why they matter. In your case, since Not (Elem x xs) simply means a function Elem x xs -> Void, this is where the "type being defined occurring on the left-hand side of an arrow" comes from.

Can you make do with something like this?

mutual
  data Set : Type -> Type where
    Empty : Set a
    Insert : (x : a) -> (xs : Set a) -> NotElem x xs -> Set a

  data NotElem : (x : a) -> Set a -> Type where
    NotInEmpty : NotElem x Empty
    NotInInsert : Not (x = y) -> NotElem x ys -> NotElem x (Insert y ys p)
Community
  • 1
  • 1
Cactus
  • 27,075
  • 9
  • 69
  • 149
  • 1
    Okay, I think I get it now and your suggestion is exactly the kind of "I did not even think of this" answer I was hoping for, thank you! :) – Julian Kniephoff Jul 22 '16 at 08:13
  • 1
    Sorry, I was a bit too quick, there. `Empty` and `Insert` are total now, but I still get the same error as before for `NotInEmpty` and `NotInInsert`. Does this have a different reason now? Also how can the `Set` constructors be total when something they refer to is not (shown to be)? – Julian Kniephoff Jul 22 '16 at 08:23
  • @JulianKniephoff: Hmmm... yes, I managed to reproduce that. I am not seeing why this definition of `NotElem` is problematic. – Cactus Jul 26 '16 at 06:25
  • The issue is that `Not (x = y)` is actually a shortcut for `(x = y) -> Void` and you came back to the same issue. – Nicolas Jul 31 '16 at 12:34
  • @Nicolas: yeah but the `x` and `y` there are `a`, not `Set a`. – Cactus Jul 31 '16 at 13:56