Type Level Fix Point while Ensuring Termination - idris

It is possible to represent to some how make unFix total? Possibly by restricting what f is?
record Fix (f : Type -> Type) where
constructor MkFix
unFix : f (Fix f)
> :total unFix
Fix.unFix is possibly not total due to:
MkFix, which is not strictly positive

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 Containers 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.

Related

Encoding for higher order functors with Lightweight higher-kinded polymorphism

OCaml unfortunately doesn't accept type variables ranging over type constructors :
'a option, 'a list are valid, but 'a 'm is not.
Thanks to functors (cf so/Fix data type in OCaml) we can encode fix point and range over type constructor.
We can also avoid using modules, and use only value-level Ocaml (Lightweight higher kind cf higher and higher_kind )
Some data structure like perfect trees can be described as a fixpoint of a "higher order functor" : the equivalent to the "underlying type constructor", before taking the fixpoint, maps a type constructor (p: * -> *) to another type constructor * -> *.
Can we encode perfect trees as such a fixpoint using the value-level (LHK) approach of the higher/higher_kind library ?
Perfect = Mu1 (p : *->*). Id + p ∘ Δ
where
Δ : * -> *
type Δ a = (a,a)
in haskell
-- stack --resolver lts-17.10 script
{-# LANGUAGE StandaloneKindSignatures #-}
module SOPerfectTree where
type Perfect :: * -> *
type Perfect a = Mu1 PerfectF a
type Mu1 :: ((* -> *) -> * -> *) -> * -> *
newtype Mu1 f a = In {unIn :: f (Mu1 f) a}
type PerfectF :: (* -> *) -> * -> *
data PerfectF f a = Leaf a | Node (f (a, a))

How do you operate on dependent pairs in a proof?

This is a follow up to this question. Thanks to Kwartz I now have a state of the proposition if b divides a then b divides a * c for any integer c, namely:
alsoDividesMultiples : (a, b, c : Integer) ->
DivisibleBy a b ->
DivisibleBy (a * c) b
Now, the goal has been to prove that statement. I realized that I do not understand how to operate on dependent pairs. I tried a simpler problem, which was show that every number is divisible by 1. After a shameful amount of thought on it, I thought I had come up with a solution:
-- All numbers are divisible by 1.
DivisibleBy a 1 = let n = a in
(n : Integer ** a = 1 * n)
This compiles, but I was had doubts it was valid. To verify that I was wrong, it changed it slightly to:
-- All numbers are divisible by 1.
DivisibleBy a 1 = let n = a in
(n : Integer ** a = 2 * n)
This also compiles, which means my "English" interpretation is certainly incorrect, for I would interpret this as "All numbers are divisible by one since every number is two times another integer". Thus, I am not entirely sure what I am demonstrating with that statement. So, I went back and tried a more conventional way of stating the problem:
oneDividesAll : (a : Integer) ->
(DivisibleBy a 1)
oneDividesAll a = ?sorry
For the implementation of oneDividesAll I am not really sure how to "inject" the fact that (n = a). For example, I would write (in English) this proof as:
We wish to show that 1 | a. If so, it follows that a = 1 * n for some n. Let n = a, then a = a * 1, which is true by identity.
I am not sure how to really say: "Consider when n = a". From my understanding, the rewrite tactic requires a proof that n = a.
I tried adapting my fallacious proof:
oneDividesAll : (a : Integer) ->
(DivisibleBy a 1)
oneDividesAll a = let n = a in (n : Integer ** a = b * n)
But this gives:
|
12 | oneDividesAll a = let n = a in (n : Integer ** a = b * n)
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When checking right hand side of oneDividesAll with expected type
DivisibleBy a 1
Type mismatch between
Type (Type of DPair a P)
and
(n : Integer ** a = prim__mulBigInt 1 n) (Expected type)
Any help/hints would be appreciated.
First off, if you want to prove properties on number, you should use Nat (or other inductive types). Integer uses primitives that the argument can't argue further than prim__mulBigInt : Integer -> Integer -> Integer; that you pass two Integer to get one. The compiler doesn't know anything how the resulting Integer looks like, so it cannot prove stuff about it.
So I'll go along with Nat:
DivisibleBy : Nat -> Nat -> Type
DivisibleBy a b = (n : Nat ** a = b * n)
Again, this is a proposition, not a proof. DivisibleBy 6 0 is a valid type, but you won't find a proof : Divisible 6 0. So you were right with
oneDividesAll : (a : Nat) ->
(DivisibleBy a 1)
oneDividesAll a = ?sorry
With that, you could generate proofs of the form oneDividesAll a : DivisibleBy a 1. So, what comes into the hole ?sorry? :t sorry gives us sorry : (n : Nat ** a = plus n 0) (which is just DivisibleBy a 1 resolved as far as Idris can). You got confused on the right part of the pair: x = y is a type, but now we need a value – that's what's your last error cryptic error message hints at). = has only one constructor, Refl : x = x. So we need to get both sides of the equality to the same value, so the result looks something like (n ** Refl).
As you thought, we need to set n to a:
oneDividesAll a = (a ** ?hole)
For the needed rewrite tactic we check out :search plus a 0 = a, and see plusZeroRightNeutral has the right type.
oneDividesAll a = (a ** rewrite plusZeroRightNeutral a in ?hole)
Now :t hole gives us hole : a = a so we can just auto-complete to Refl:
oneDividesAll a = (a ** rewrite plusZeroRightNeutral a in Refl)
A good tutorial on theorem proving (where it's also explained why plus a Z does not reduce) is in the Idris Doc.

Why is filter based on dependent pair?

In the Idris Tutorial a function for filtering vectors is based on dependent pairs.
filter : (a -> Bool) -> Vect n a -> (p ** Vect p a)
filter f [] = (_ ** [])
filter f (x :: xs) with (filter f xs )
| (_ ** xs') = if (f x) then (_ ** x :: xs') else (_ ** xs')
But why is it necessary to put this in terms of a dependent pair instead of something more direct such as?
filter' : (a -> Bool) -> Vect n a -> Vect p a
In both cases the type of p must be determined, but in my supposed alternative the redundancy of listing p twice is eliminated.
My naive attempts at implementing filter' failed, so I was wondering is there a fundamental reason that it can't be implemented? Or can filter' be implemented, and perhaps filter was just a poor example to showcase dependent pairs in Idris? But if that is the case then in what situations would dependent pairs be useful?
Thanks!
The difference between filter and filter' is between existential and universal quantification. If (a -> Bool) -> Vect n a -> Vect p a was the correct type for filter, that would mean filter returns a Vector of length p and the caller can specify what p should be.
Kim Stebel's answer is right on the money. Let me just note that this was already discussed on the Idris mailing list back in 2012 (!!):
filter for vector, a question - Idris Programming Language
What raichoo posted there can help clarifying it I think; the real signature of your filter' is
filter' : {p : Nat} -> {n: Nat} -> {a: Type} -> (a -> Bool) -> Vect a n -> Vect a p
from which it should be obvious that this is not what filter should (or even could) do; p actually depends on the predicate and the vector you are filtering, and you can (actually need to) express this using a dependent pair. Note that in the pair (p ** Vect p a), p (and thus Vect p a) implicitly depends on the (unnamed) predicate and vector appearing before it in its signature.
Expanding on this, why a dependent pair? You want to return a vector, but there's no "Vector with unknown length" type; you need a length value for obtaining a Vector type. But then you can just think "OK, I will return a Nat together with a vector with that length". The type of this pair is, unsurprisingly, an example of a dependent pair. In more detail, a dependent pair DPair a P is a type built out of
A type a
A function P: a -> Type
A value of that type DPair a P is a pair of values
x: a
y: P a
At this point I think that is just syntax what might be misleading you. The type p ** Vect p a is DPair Nat (\p => Vect p a); p there is not a parameter for filter or anything like it. All this can be a bit confusing at first; if so, maybe it helps thinking of p ** Vect p a as a substitute for the "Vector with unknown length" type.
Not an answer, but additional context
Idris 1 documentation - https://docs.idris-lang.org/en/latest/tutorial/typesfuns.html#dependent-pairs
Idris 2 documentation - https://idris2.readthedocs.io/en/latest/tutorial/typesfuns.html?highlight=dependent#dependent-pairs
In Idris 2 the dependent pair defined here
and is similar to Exists and Subset but BOTH of it's values are NOT erased at runtime

How do I define the property of a function being its own inverse in Idris?

I want to be able to say, for a function of f with signature t->t, that for all x in t, f(f(x)) = x.
When I run this:
%default total
-- The type of parity values - either Even or Odd
data Parity = Even | Odd
-- Even is the opposite of Odd and Odd is the opposite of Even
opposite: Parity -> Parity
opposite Even = Odd
opposite Odd = Even
-- The 'opposite' function is it's own inverse
opposite_its_own_inverse : (p : Parity) -> opposite (opposite p) = p
opposite_its_own_inverse Even = Refl
opposite_its_own_inverse Odd = Refl
-- abstraction of being one's own inverse
IsItsOwnInverse : {t : Type} -> (f: t->t) -> Type
IsItsOwnInverse {t} f = (x: t) -> f (f x) = x
opposite_IsItsOwnInverse : IsItsOwnInverse {t=Parity} opposite
opposite_IsItsOwnInverse = opposite_its_own_inverse
I get this error message:
- + Errors (1)
`-- own_inverse_example.idr line 22 col 25:
When checking right hand side of opposite_IsItsOwnInverse with expected type
IsItsOwnInverse opposite
Type mismatch between
(p : Parity) ->
opposite (opposite p) = p (Type of opposite_its_own_inverse)
and
(x : Parity) -> opposite (opposite x) = x (Expected type)
Specifically:
Type mismatch between
opposite (opposite v0)
and
opposite (opposite v0)
Am I doing something wrong, or is that just a bug?
If I replace the last 'opposite_its_own_inverse' with '?hole', I get:
Holes
This buffer displays the unsolved holes from the currently-loaded code. Press
the [P] buttons to solve the holes interactively in the prover.
- + Main.hole [P]
`-- opposite : Parity -> Parity
-------------------------------------------------------
Main.hole : (x : Parity) -> opposite (opposite x) = x
The name for this property is an involution. Your type for this property is pretty good but I like writing it like so:
Involution : (t -> t) -> t -> Type
Involution f x = f (f x) = x
The first problem with your opposite_IsItsOwnInverse is that you haven't fully applied Involution so you haven't yet gotten a type. You also need apply a Parity so that Involution gives a Type, like so:
opposite_IsItsOwnInverse : Involution opposite p
That p is an implicit argument. Implicit arguments are implicitly created by lowercase identifiers in type signatures. This is like writing:
opposite_IsItsOwnInverse : {p : Parity} -> Involution opposite p
But this leads to another problem with the signature - opposite is also lowercase, so it's getting treated as an implicit argument! (This is why you get the confusing error message, Idris has created another variable called opposite) You have 2 possible solutions here: qualify the identifier, or use an identifier which starts with an uppercase letter.
I'll assume the module you're writing uses the default name of Main. The final type signature looks like:
opposite_IsItsOwnInverse : Involution Main.opposite p
And the implementation will just use the implicit argument and supply it to the function you've already written:
opposite_IsItsOwnInverse {p} = opposite_its_own_inverse p

Idris: Force vector sums to be equal

I am trying to learn Idris by rebuilding (in a more simple manner) some stuff we recently did at work.
I would like to have a data type that models a general ledger with a vector of credits and a vector of debits. I have gotten this far:
data GL : Type where
MkGL : (credits : Vect n Integer) ->
(debits : Vect m Integer) ->
(sum credits = sum debits) ->
GL
emptyGL : GL
emptyGL = MkGL [] [] Refl
but I am not sure how to add records to an already existing GL.
With a function like
addTransactions : GL -> (Vect j Integer) -> (Vect k Integer) -> Maybe GL
How do I check/enforce that the new GL plays by the rules?
I think the way I would handle this situation would be to create a new datatype to represent vectors of integers with a given total value, like so:
||| A Vector of Integers with a given sum total
data iVect : Nat -> Integer -> Type where
iZero : iVect 0 0
iAdd : (x : Integer) -> iVect n y -> iVect (S n) (y + x)
data GL : Type where
MkGL : (credits : iVect n s) ->
(debits : iVect m s) ->
GL
emptyGL : GL
emptyGL = MkGL iZero iZero
You may want to define an additional function for more convenient updating of a GT but you get the idea. Now the equality of the credits and debits is enforced by the type system without creating a burdensome obligation to explicitly prove that the sums of two arbitrary vectors are in fact equal every time you want to construct a GL. They amount to the same thing anyway, but what I'm describing is a much more practical way to do it.