The problem here is that Idris has no way of knowing that the base functor you are using for your datatype is strictly positive. If it were to accept your definition, you could then use it with a concrete, negative functor and prove Void from it.

There are two ways to represent strictly positive functors: by defining a universe or by using containers. I have put everything in two self-contained gists (but there are no comments there).

A Universe of Strictly Positive Functors

You can start with a basic representation: we can decompose a functor into either a sigma type ( Sig ), a (strictly-positive) position for a recursive substructure ( Rec ) or nothing at all ( End ). This gives us this description and its decoding as a Type -> Type function:

-- A universe of positive functor data Desc : Type where Sig : (a : Type) -> (a -> Desc) -> Desc Rec : Desc -> Desc End : Desc -- The decoding function desc : Desc -> Type -> Type desc (Sig a d) x = (v : a ** desc (d v) x) desc (Rec d) x = (x, desc d x) desc End x = ()

Once you have this universe of functors which are guaranteed to be strictly positive, you can take their least fixpoint:

-- The least fixpoint of such a positive functor data Mu : Desc -> Type where In : desc d (Mu d) -> Mu d

You can now define your favourite datatype.

Example: Nat

We start with a sum type of tags for each one of the constructors.

data NatC = ZERO | SUCC

We then define the strictly positive base functor by storing the constructor tag in a sigma and computing the rest of the description based on the tag value. The ZERO tag is associated to End (there is nothing else to store in a zero constructor) whilst the SUCC one demands a Rec End , that is to say one recursive substructure corresponding to the Nat's predecessor.

natD : Desc natD = Sig NatC $ \ c => case c of ZERO => End SUCC => Rec End

Our inductive type is then obtained by taking the fixpoint of the description:

nat : Type nat = Mu natD

We can naturally recover the constructors we expect:

zero : nat zero = In (ZERO ** ()) succ : nat -> nat succ n = In (SUCC ** (n, ()))

References

This specific universe is taken from 'Ornamental Algebras, Algebraic Ornaments' by McBride but you can find more details in 'The Gentle Art of Levitation' by Chapman, Dagand, McBride, and Morris.

Strictly Positive Functors as the Extension of Containers

The second representation is based on another decomposition: each inductive type is seen as a general shape (i.e. its constructors and the data they store) plus a number of recursive positions (which can depend on the specific value of the shape).

record Container where constructor MkContainer shape : Type position : shape -> Type

Once more we can give it an interpretation as a Type -> Type function:

container : Container -> Type -> Type container (MkContainer s p) x = (v : s ** p v -> x)

And take the fixpoint of the strictly positive functor thus defined:

data W : Container -> Type where In : container c (W c) -> W c

You can once more recover your favourite datatypes by defining Container s of interest.

Example: Nat

Natural numbers have two constructors, each storing nothing at all. So the shape will be a Bool . If we are in the zero case then there are no recursive positions ( Void ) and in the succ one there is exactly one ( () ).

natC : Container natC = MkContainer Bool (\ b => if b then Void else ())

Our type is obtained by taking the fixpoint of the container:

nat : Type nat = W natC

And we can recover the usual constructors:

zero : nat zero = In (True ** \ v => absurd v) succ : nat -> nat succ n = In (False ** \ _ => n)

References

This is based on 'Containers: Constructing Strictly Positive Types' by Abbott, Altenkirch, and Ghani.