Recently I've been needing congβ so I figured I might as well check whether I can
write a generic version. After playing type cosmonaut for a bit, here we are:
open import Relation.Binary.PropositionalEquality as P using (_β‘_; refl)
open import Data.Vec
open import Data.Vec.All
open import Data.Product
open import Data.Unit
open import Function
open import Level
toLevel : β {n} β Vec Level n β Level
toLevel = foldr _ _β_ zero
Sets : β {n} (ls : Vec Level n) β Set (suc (toLevel ls))
Sets [] = Lift _ β€
Sets (l β· ls) = Set l Γ Sets ls
arrows : β {n r} (ls : Vec Level n) β Sets ls β Set r β Set (toLevel ls β r)
arrows [] ds c = c
arrows (l β· ls) (d , ds) c = d β arrows ls ds c
eqs : β {n r} (ls : Vec Level n) (ds : Sets ls) {c : Set r} β
(f g : arrows ls ds c) β Set (toLevel ls β r)
eqs [] ds f g = f β‘ g
eqs (l β· ls) (d , ds) f g = {x y : d} β x β‘ y β eqs ls ds (f x) (g y)
cong : β n {ls : Vec Level n} {ds : Sets ls} {r} (c : Set r) β
(f : arrows ls ds c) β eqs ls ds f f
cong _ {[]} c f = refl
cong _ {l β· ls} c f refl = cong _ {ls} c (f _)
-- test case
data Tree {l} (A : Set l) : Set l where
node : Tree β€ β Tree A Γ Tree (A Γ A) β β€ β Tree A β
(Vec β€ 2 β Tree (Vec A 5)) β Tree A
_ : β {k l m n p q r s t u} β node k l m n p β‘ node q r s t u
_ = cong 5 (Tree (Lift (suc (suc zero)) β€)) node {!!} {!!} {!!} {!!} {!!}
As you'll have noticed you need to specify the return type of the constructor for
inference to work. I don't think we can get anything better without resorting to
reflection to inspect the goal directly: there is no reason for Agda to assume the
constructor is fully applied.
Thoughts?
Somewhat related: #10
Nevermind my previous comment: it is possible to get even more from the unifier by
not using a Vec Level n but rather an equivalent definition which can get solved
via eta-expansion & unification.
If we define everything by induction on the natural number then we don't need to
specify the return type: it is whatever is leftover after the first n argument
types have been used.
open import Relation.Binary.PropositionalEquality as P using (_β‘_; refl)
open import Data.Unit
open import Data.Product
open import Level as L hiding (zero; suc)
open import Data.Nat.Base
Levels : β β Set
Levels zero = β€
Levels (suc n) = Level Γ Levels n
toLevel : β n β Levels n β Level
toLevel zero ls = L.zero
toLevel (suc n) (l , ls) = l L.β toLevel n ls
Sets : β n (ls : Levels n) β Set (L.suc (toLevel n ls))
Sets zero ls = Lift _ β€
Sets (suc n) (l , ls) = Set l Γ Sets n ls
arrows : β n {r} (ls : Levels n) β Sets n ls β Set r β Set (toLevel n ls L.β r)
arrows zero ls ds c = c
arrows (suc n) (l , ls) (d , ds) c = d β arrows n ls ds c
eqs : β n {r} (ls : Levels n) (ds : Sets n ls) {c : Set r} β
(f g : arrows n ls ds c) β Set (toLevel n ls L.β r)
eqs zero ls ds f g = f β‘ g
eqs (suc n) (l , ls) (d , ds) f g = {x y : d} β x β‘ y β eqs n ls ds (f x) (g y)
cong : β n {ls : Levels n} {ds : Sets n ls} {r} {c : Set r} β
(f : arrows n ls ds c) β eqs n ls ds f f
cong zero f = refl
cong (suc n) f refl = cong n (f _)
-- test case
open import Data.Vec
data Tree {l} (A : Set l) : Set l where
node : A β Tree β€ β Tree A Γ Tree (A Γ A) β β€ β
Tree A β (Vec β€ 2 β Tree (Vec A 5)) β Tree A
_ : β {k l m n p q r s t u} β node tt k l m n p β‘ node tt q r s t u
_ = cong 5 (node tt) {!!} {!!} {!!} {!!} {!!}
Haha, awesome, I've always wondered about this!
I've been trying to do similar things like write a hole operator (e.g. be able to replace Ξ» c β f a b c d e with f a b β d e). The machinery above looks like it might be useful.
Two questions. Where would we put the machinery and where would we put the new cong. For the latter I guess it should probably go in Relation.Binary.PropositionalEquality under congβ? I guess we should also try to create substβ as well.
Next up, get it to work with dependent functions :laughing:
I've been trying to do similar things like write a
holeoperator (e.g. be able to replaceΞ» c β f a b c d ewithf a b β d e). The machinery above looks like it might be useful.
Oooh, I like this idea!
Where would we put the machinery?
Good question. Some of it could go under Data.Product.N-ary.Heterogeneous. It would depart from Data.Product.N-ary which has a special case of 0 and 1 but that makes all the code more complicated without a huge benefit in my opinion.
it should probably go in
Relation.Binary.PropositionalEqualityundercongβ?
I guess we should also try to createsubstβas well.
:+1: to both
Some of it could go under Data.Product.N-ary.Heterogeneous. It would depart from Data.Product.N-ary which has a special case of 0 and 1 but that makes all the code more complicated without a huge benefit in my opinion.
:+1:
subst can indeed be defined in the same manner:
Subst : β n {r} (ls : Levels n) (ds : Sets n ls) β
(f g : arrows n ls ds (Set r)) β Set (toLevel n ls L.β r)
Subst zero ls ds f g = f β g
Subst (suc n) (l , ls) (d , ds) f g = {x y : d} β x β‘ y β Subst n ls ds (f x) (g y)
subst : β n {ls : Levels n} {ds : Sets n ls} {r} β
(f : arrows n ls ds (Set r)) β Subst n ls ds f f
subst zero f x = x
subst (suc n) f refl = subst n (f _)
postulate
C : (A B : Set) (m n : β) β Set
_ : β {A B D E m n p q} β C A B m n β C D E p q
_ = subst 4 C {!!} {!!} {!!} {!!}
Hey guys, I came across this development and I did some work related to arity-generic programming in Agda a few years ago, so I thought you might be interested.
In this Stack Overflow answer I describe how to get n-ary dependent function composition (currently stdlib only supports non-dependent n-ary functions, right?).
In this blog post I further elaborate on how to unify dependent and non-dependent representations of telescopes.
And while we're here, there is also a way to emulate cumulativity of universes which is occasionally helpful when you need to deal with n-ary functions.
I've also implemented n-ary cong here in a composable way (e.g. one can apply congn to itself and that will type check perfectly, which I think is not the case with the current stdlib implementation of n-ary cong).
Hope that can be helpful.
Most helpful comment
substcan indeed be defined in the same manner: