How does the order of implicit arguments affect idris? - idris

This fails:
> the ({A : Type} -> A -> {B : Type} -> B -> (A, B)) MkPair
(input):1:5:When checking argument value to function Prelude.Basics.the:
Type mismatch between
A -> B1 -> (A, B1) (Type of MkPair)
and
A1 -> B -> (A1, B) (Expected type)
Specifically:
Type mismatch between
Pair A
and
\uv => uv -> uv
This works:
> ({A : Type} -> {B : Type} -> A -> B -> (A, B)) MkPair
\A1, B1 => MkPair : A -> B -> (A, B)
Oddly:
q : {A : Type} -> A -> {B : Type} -> B -> (A, B)
q a b = MkPair a b
> :t q
q : A -> B -> (A, B)
> :t MkPair
MkPair : A -> B -> (A, B)
Why do q and MkPair appear to have the same type? Do they really have the same type? Why does the order of implicit arguments matter?

In some sense implicit arguments are no different from non-implicit ones. The compiler infers them for you most of the time, but they are still arguments and must be present because at the level of the core language there are no implicit arguments. You can ask REPL to show implicits for you:
λΠ> :set showimplicits
λΠ> :t MkPair
Builtins.MkPair : {A : Type} -> {B : Type} -> (a : A) -> (b : B) -> (A, B)
λΠ> :t q
Main.q : {A : Type} -> A -> {B : Type} -> B -> (A, B)
If you substitute ordinary parentheses for curly braces in the above types, you'll see that the types of MkPair and q are different because of the different order of their parameters.

Related

How to prove equality commutes in Idris?

Trying to prove the following assertion:
equalityCommutesNat : (n : Nat) -> (m : Nat) -> n = m -> m = n
I found plusCommutes in the libraries but nothing for equality.
The only inhabitant of = is Refl : (a = a), so if you pattern match, you'll get evidence that n is m.
Which means you can then use Refl, since Idris's pattern matching now knows they're the same:
equalityCommutesNat : (n : Nat) -> (m : Nat) -> n = m -> m = n
equalityCommutesNat _ _ Refl = Refl
And you can play around with this in the REPL:
> equalityCommutesNat 1 1 Refl
Refl : 1 = 1

Strange compiler error: Cannot unify constraint with constraint1

I am trying to write a library in Idris to work with categories and functors. For my use case, each type can be a category in at most one way (and I would like to use overloading for id and .), so using an interface suits my needs:
infixr 9 .
interface CategoryI (o : Type) where
data Hom : o -> o -> Type
(.) : {a : o} -> {b : o} -> {c : o} -> Hom b c -> Hom a b -> Hom a c
id : (a : o) -> Hom a a
However, for functors, I need a datatype rather than an interface, since there can be multiple functors between the same two categories that I would like to consider.
data Functor : Type -> Type -> Type where
MkFunctor : (CategoryI s, CategoryI t) =>
(f : s -> t)
-> (Hom x y -> Hom (f x) (f y))
-> Functor s t
To make use of this, I have written accesser functions:
src : Functor s t -> Type
src (MkFunctor fo fm) = s
tgt : Functor s t -> Type
tgt (MkFunctor fo fm) = t
f_obj : (CategoryI s, CategoryI t) => Functor s t -> (s -> t)
f_obj (MkFunctor fo fm) = fo
But I am having problems with the following:
f_map : (CategoryI s, CategoryI t) => (f : Functor s t)
-> (Hom x y -> Hom ((f_obj f) x) ((f_obj f) y))
f_map (MkFunctor fo fm) = fm
The compiler complains:
When checking right hand side of f_map with expected type
Hom x y -> Hom (f_obj (MkFunctor fo fm) x) (f_obj (MkFunctor fo fm) y)
Type mismatch between
Hom x y -> Hom (fo x) (fo y) (Type of fm x y)
and
Hom x y -> Hom (fo x) (fo y) (Expected type)
Specifically:
Type mismatch between
constraint1
and
constraint
I can't even determine what the compiler is complaining abut here. IT somehow can't unify two constraints (which ones?), but the constraints on my constructor and on my f_map function are the same, so I don't see what the issue is.
How can I resolve this issue?

Understanding Argument Type

What's the meaning of this (a, b, c: Nat) argument in:
g : (a, b, c: Nat) -> Int
g (a,b,c) = 42
?
Evidently the first argument is a triple, i.e. 3-tuple.
g: (a,b,c: Nat) -> Int
is just a short cut for
g: (a: Nat) -> (b: Nat) -> (c: Nat) -> Int
If you expand on g: (a,b,c: Nat) -> Int you will get
g: (a, b, c: Nat) -> Int
g a b c = ?g_rhs
A named tuple parameter (AFAIK idris does not have built-in triples) would be specified as
g: (a: (Nat, Nat)) -> Int
g a = ?g_rhs

Multi-Parameter Sub-Classes in Idris

Inspired by this blog post and this code I thought I'd try some category theory in Idris using its interfaces (type-classes).
I defined Category as follows, which works fine:
interface Category (obj : Type) (hom : obj -> obj -> Type) where
id : {a : obj} -> hom a a
comp : {a, b, c : obj} -> hom b c -> hom a b -> hom a c
Then, in the spirit of the Verified module, I thought I'd define a verified category:
interface Category obj hom =>
VerifiedCategory (obj : Type) (hom : obj -> obj -> Type) where
categoryAssociativity : {a, b, c, d : obj} ->
(f : hom c d) -> (g : hom b c) -> (h : hom a b) ->
(comp (comp f g) h = comp f (comp g h))
categoryLeftIdentity : {a, b : obj} -> (f : hom a b) -> (comp id f = f)
categoryRightIdentity : {a, b : obj} -> (f : hom a b) -> (comp f id = f)
Unfortunately, Idris rejects that code with the following error message:
When checking type of constructor of CategoryTheory.VerifiedCategory:
Can't find implementation for Category obj hom
Am I doing something wrong, or am I trying to do something with multi-parameter sub-classes that Idris cannot do?
All this code is in its own module, called CategoryTheory, without any imports.
I'm working with Idris v0.12.
I don't know why (and would be very curious to find out!) but it works if you specify all the implicit arguments to id and comp in VerifiedCategory explicitly. It is pretty ugly and tedious to figure out, but this typechecks:
interface Category obj hom => VerifiedCategory (obj : Type) (hom : obj -> obj -> Type) where
categoryAssociativity : {a, b, c, d : obj} ->
(f : hom c d) ->
(g : hom b c) ->
(h : hom a b) ->
(comp {a = a} {b = b} {c = d} (comp {a = b} {b = c} {c = d} f g) h = comp {a = a} {b = c} {c = d} f (comp {a = a} {b = b} {c = c} g h))
categoryLeftIdentity : {a, b : obj} ->
(f : hom a b) ->
(comp {a = a} {b = b} {c = b} (id {a = b}) f = f)
categoryRightIdentity : {a, b : obj} ->
(f : hom a b) ->
(comp {a = a} {b = a} {c = b} f (id {a = a}) = f)
Edit: Another way I just found is to explicitly designate hom as a determining parameter, i.e. the parameter of the type class that is sufficient to find an implementation. This has to happen in Category as well as in VerifiedCategory (I'm not sure, why), like so:
interface Category (obj : Type) (hom : obj -> obj -> Type) | hom where
-- ...
interface Category obj hom => VerifiedCategory (obj : Type) (hom : obj -> obj -> Type) where
-- ...
i.e. by putting a | hom before the where.
One thing you have to do in addition to that is qualify the usage of id in VerifiedCategory, because otherwise it is interpreted as implicit parameter for whatever reason:
categoryLeftIdentity : {a, b : obj} ->
(f : hom a b) ->
comp CategoryTheory.id f = f
categoryRightIdentity : {a, b : obj} ->
(f : hom a b) ->
comp f CategoryTheory.id = f
See also this reddit thread that might be illuminating in the future.

Promoting free variables in type terms to implicit function arguments

In order for my question to be meaningful, I must provide some background.
I think it would be useful to have a dependently typed language that can infer the existence and type of an argument a for a function whose other parameters and/or return value have types that depend on a. Consider the following snippet in a language I am designing:
(* Backticks are used for infix functions *)
def Cat (`~>` : ob -> ob -> Type) :=
sig
exs id : a ~> a
exs `.` : b ~> c -> a ~> b -> a ~> c
exs lid : id . f = f
exs rid : f . id = f
exs asso : (h . g) . f = h . (g . f)
end
If we make two (admittedly, unwarranted) assumptions:
No dependencies must exist that cannot be inferred from explicitly provided information.
Every free variable must be converted into an implicit argument of the last identifier introduced using def or exs.
We can interpret the above snippet as being equivalent to the following one:
def Cat {ob} (`~>` : ob -> ob -> Type) :=
sig
exs id : all {a} -> a ~> a
exs `.` : all {a b c} -> b ~> c -> a ~> b -> a ~> c
exs lid : all {a b} {f : a ~> b} -> id . f = f
exs rid : all {a b} {f : a ~> b} -> f . id = f
exs asso : all {a b c d} {f : a ~> b} {g} {h : c ~> d}
-> (h . g) . f = h . (g . f)
end
Which is more or less the same as the following Agda snippet:
record Cat {ob : Set} (_⇒_ : ob → ob → Set) : Set₁ where
field
id : ∀ {a} → a ⇒ a
_∙_ : ∀ {a b c} → b ⇒ c → a ⇒ b → a ⇒ c
lid : ∀ {a b} {f : a ⇒ b} → id ∙ f ≡ f
rid : ∀ {a b} {f : a ⇒ b} → f ∙ id ≡ f
asso : ∀ {a b c d} {f : a ⇒ b} {g} {h : c ⇒ d} → (h ∙ g) ∙ f ≡ h ∙ (g ∙ f)
Clearly, two unwarranted assumptions have saved us a lot of typing!
Note: Of course, this mechanism only works as long as the original assumptions hold. For example, we cannot correctly infer the implicit arguments of the dependent function composition operator:
(* Only infers (?2 -> ?3) -> (?1 -> ?2) -> (?1 -> ?3) *)
def `.` g f x := g (f x)
In this case, we have to explicitly provide some additional information:
(* If we omitted {x}, it would become an implicit argument of `.` *)
def `.` (g : all {x} (y : B x) -> C y) (f : all x -> B x) x := g (f x)
Which can be expanded into the following:
def `.` {A} {B : A -> Type} {C : all {x} -> B x -> Type}
(g : all {x} (y : B x) -> C y) (f : all x -> B x) x := g (f x)
Here is the equivalent Agda definition, for comparison:
_∘_ : ∀ {A : Set} {B : A → Set} {C : ∀ {x} → B x → Set}
(g : ∀ {x} (y : B x) → C y) (f : ∀ x → B x) x → C (f x)
(g ∘ f) x = g (f x)
End of Note
Is the mechanism described above feasible? Even better, is there any language that implements something resembling this mechanism?
This sounds like implicit generalization in Coq.