Handling substitutions of mutually defined types with Agda's standard library's Data.Fin.Substitution - substitution

I'm trying to encode a call-by-push-value lambda calculus with isorecursive types in Agda. So I mutually define value types and computation types with up to n free value type variables (I only need to substitute value types for the isorecursive types) as follows (this is just a fragment).
data VType (n : ℕ) : Set where
vunit : VType n -- unit type
var : Fin n → VType n -- type variable
u : CType n → VType n -- thunk
μ : VType (1 + n) → VType n -- isorecursive type
data CType (n : ℕ) : Set where
_⇒_ : VType n → CType n → CType n -- lambda abstraction
f : VType n → CType n -- a value-producer
In the style here, I want to be able to do substitutions like
example : CType 0
example = f (var (# 0)) C[/ vunit ]
where
_C[/_] : ∀ {n} → CType (1 + n) → VType n → CType n
ct [/ vt ] = ?
post-substitutes vt into ct. Notice I want to substitute a value type into a computation type. I am able to use the standard library to substitute VTypes into VTypes, but not VTypes into CTypes, like above. I do that like so, using Data.Fin.Substitution (see here):
module TypeSubst where
-- Following Data.Substitutions.Example
module TypeApp {T} (l : Lift T VType) where
open Lift l hiding (var)
-- Applies a substitution to a type
infixl 8 _/v_
_/v_ : ∀ {m n} → VType m → Sub T m n → VType n
_/c_ : ∀ {m n} → CType m → Sub T m n → CType n
vunit /v ρ = vunit
(var x) /v ρ = lift (lookup x ρ)
(u σ) /v ρ = u (σ /c ρ)
(μ τ) /v ρ = μ (τ /v ρ ↑)
(σ ⇒ τ) /c ρ = σ /v ρ ⇒ τ /c ρ
f x /c ρ = f (x /v ρ)
open Application (record { _/_ = _/v_ }) using (_/✶_)
typeSubst : TermSubst VType
typeSubst = record { var = var; app = TypeApp._/v_ }
open TermSubst typeSubst public hiding (var)
weaken↑ : ∀ {n} → VType (1 + n) → VType (2 + n)
weaken↑ τ = τ / wk ↑
infix 8 _[/_]
-- single type substitution
_[/_] : ∀ {n} → VType (1 + n) → VType n → VType n
τ [/ σ ] = τ / sub σ
I've tried working with a new datatype Type:
data VorC : Set where
v : VorC
c : VorC
data Type : VorC → ℕ → Set where
vtype : ∀ {n} → VType n → Type v n
ctype : ∀ {n} → CType n → Type c n
I tried using the natural unwrapping function to go from Types to VType's or CType's, but this doesn't seem to work or leads to termination checking problems if I try mimicking the standard library's module.
Does anyone know if it is possible to use Data.Fin.Substitution from the standard library to accomplish something like this? Could someone explain that module to me? There is no documentation on this... If it isn't possible to use the standard library for this, any pointers on how to approach this problem is also welcome. Thanks!

You can open Application in the CType case instead of opening TermSubst which looks inappropriate (I don't know what's wrong with it). Here is the relevant part:
typeSubst : TermSubst VType
typeSubst = record { var = var; app = TypeApp._/v_ }
open TermSubst typeSubst public hiding (var)
module TypeSubst where
_[/v_] : ∀ {n} → VType (1 + n) → VType n → VType n
τ [/v σ ] = τ / sub σ
open Application (record { _/_ = TypeApp._/c_ termLift }) renaming (_/_ to _/c_) using ()
_[/c_] : ∀ {n} → CType (1 + n) → VType n → CType n
τ [/c σ ] = τ /c sub σ
The whole code.
To understand what's going in the standard library you need to read the Type-Preserving Renaming and Substitution paper. Though, the code in stdlib is quite more abstract.
BTW, you can use order preserving embeddings to define renaming and renaming to define substitution. Fill the holes here.

Related

Increment binary value type by one

I want to increment a binary value by one, but I'm still not very familiar with how recursion in agda works.
Why aren't I getting the right output here?
Bin Type Definition
data Bin : Set where
⟨⟩ : Bin
_O : Bin → Bin
_I : Bin → Bin
My increment function
inc : Bin → Bin
inc ⟨⟩ = ⟨⟩ I
inc (x O) = ⟨⟩ I
inc (x I) = (inc x) I
A quick correction of your algorithm
Your increment function is not correct. Considering your definition of binary numbers:
data Bin : Set where
⟨⟩ : Bin
_O : Bin → Bin
_I : Bin → Bin
Your increment function should be written as follows:
inc : Bin → Bin
inc ⟨⟩ = ⟨⟩ I
inc (x O) = x I
inc (x I) = (inc x) O
When the right number is zero, you just replace it by one, but you must not forget to keep the left part of the number.
When the right number is 1, you have to keep incrementing its left part, but you also need to transform this 1 into a 0.
A quick validation of the new algorithm
But, don't take my word for it, let us try and (partially) validate our function. After all, we are in a proof assistant, aren't we ?
A good way to validate such a function is to assess which property it should provide. The result of your incremental function has to be equal to 1 plus its input value. Agda provides natural numbers so let us transform your binary numbers into naturals to check such a property. First, some imports:
open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality
Then a function which transforms a binary number into a natural number:
_↑ : Bin → ℕ
⟨⟩ ↑ = 0
(x O) ↑ = x ↑ + x ↑
(x I) ↑ = suc (x ↑ + x ↑)
Finally, our validation property:
prop : ∀ {b} → (inc b) ↑ ≡ suc (b ↑)
prop {⟨⟩} = refl
prop {b O} = refl
prop {b I} rewrite prop {b} | +-suc (b ↑) (b ↑) = refl
This validation is of course incomplete (by nature) but at least it gives you confidence in your algorithm. You should always try and prove such assumptions when writing algorithms, which is the whole point of Agda (well, not the whole point, but at least part of it).
More on validation
To further make my point, I decided to try and keep validating your representation of binary numbers by implementing the reciprocal transformation from naturals to binary numbers:
_↓ : ℕ → Bin
zero ↓ = ⟨⟩
suc n ↓ = inc (n ↓)
We can directly prove that the two transformations are reciprocal when going up then down:
↑↓ : ∀ {n} → (n ↓) ↑ ≡ n
↑↓ {zero} = refl
↑↓ {suc n} rewrite prop {n ↓} | ↑↓ {n} = refl
Then I tried to do the other way around:
↓↑ : ∀ {b} → (b ↑) ↓ ≡ b
↓↑ {⟨⟩} = refl
↓↑ {b O} rewrite prop₂ {b ↑} rewrite ↓↑ {b} = refl
↓↑ {b I} rewrite prop₂ {b ↑} rewrite ↓↑ {b} = refl
This side needs prop₂ which has the following signature:
prop₂ : ∀ {n} → (n + n) ↓ ≡ (n ↓) O
This property should be true (in the sense that the binary numbers as we think of them should satisfy it), but it cannot be proven in your formalism because you can represent zero in an infinite number of ways, and all these ways are not prepositionally equal (for instance, the first case of prop₂ when n is equal to 0 requires to prove ⟨⟩ ≡ (⟨⟩ O) which cannot be proven).
All in all, validation not only allows us to find faulty algorithms (or to prove algorithms correct) but it can also reveal inconsistencies or mistakes in the basics of our theories themselves (even though in this case, a quick look could have been enough to see that 0 can be represented an infinite number of different manners).
As a side note, I am not saying that there should always be a single way of representing a specific element of an abstract data type, but it surely helps, especially when working with propositional equality, which is very often required.
On another side note, I am sorry if I got a little carried away but I find these kind of topics very enlightening regarding the use of proof assistants and formal validation.
Please feel free to ask for any further explanation.
The complete (and incomplete in a way) code
module BinaryNumber where
open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality
data Bin : Set where
⟨⟩ : Bin
_O : Bin → Bin
_I : Bin → Bin
inc : Bin → Bin
inc ⟨⟩ = ⟨⟩ I
inc (x O) = x I
inc (x I) = (inc x) O
_↑ : Bin → ℕ
⟨⟩ ↑ = 0
(x O) ↑ = x ↑ + x ↑
(x I) ↑ = suc (x ↑ + x ↑)
prop : ∀ {b} → (inc b) ↑ ≡ suc (b ↑)
prop {⟨⟩} = refl
prop {b O} = refl
prop {b I} rewrite prop {b} | +-suc (b ↑) (b ↑) = refl
_↓ : ℕ → Bin
zero ↓ = ⟨⟩
suc n ↓ = inc (n ↓)
↑↓ : ∀ {n} → (n ↓) ↑ ≡ n
↑↓ {zero} = refl
↑↓ {suc n} rewrite prop {n ↓} | ↑↓ {n} = refl
prop₂ : ∀ {n} → (n + n) ↓ ≡ (n ↓) O
prop₂ {zero} = {!!}
prop₂ {suc n} = {!!}
↓↑ : ∀ {b} → (b ↑) ↓ ≡ b
↓↑ {⟨⟩} = refl
↓↑ {b O} rewrite prop₂ {b ↑} rewrite ↓↑ {b} = refl
↓↑ {b I} rewrite prop₂ {b ↑} rewrite ↓↑ {b} = refl
The standard library
As a last remark, the binary numbers are present in the standard library in the file Data.Nat.Binary.Base with the associated properties (in particular the properties of reciprocity which are not provable in your representation) in the file Data.Nat.Binary.Properties if you feel like looking how they are implemented there.
When we define inc as Bin → Bin, we are saying that it takes values of type Bin and returns values of the same type i.e. Bin.
Since we have 3 constructors available for creating Bin, all the values of type Bin would have one of the following 3 forms:
⟨⟩
b I where b is some value of type Bin
b O where b is some value of type Bin
For case 1, since ⟨⟩ stands for zero.
inc ⟨⟩ = ⟨⟩ I
For case 2, we know that adding one to a number ending with zero will just change the last digit to one, so
inc (x O) = x I
and for case 3, when a number is ending with 1, on incrementing it we get zero at the end, and carryover is generated that needs to be passed forward. Carryover can be passed by using our same inc function. Assuming (inc x) gives a binary number, we take that output and append zero at the end.
inc (x I) = (inc x) O
Also, just to extent upon the excellent answer given by MrO, who correctly pointed out that since there are infinitely many ways to represent zeros (and all numbers)
(b ↓) ↑ = b
can't be proved for b with leading zeros before the first significant digit. But if we restrict domain of ↓↑ to only binary numbers which are only canonical i.e binary number without any leading zeros, proof can be derived.
Proof of (b ↓) ↑ = b for canonical b
Extending MrO's code,
module BinaryNumber where
open import Data.Nat
open import Data.Nat.Properties
open import Relation.Binary.PropositionalEquality
open Relation.Binary.PropositionalEquality.≡-Reasoning
data Bin : Set where
⟨⟩ : Bin
_O : Bin → Bin
_I : Bin → Bin
inc : Bin → Bin
inc ⟨⟩ = ⟨⟩ I
inc (x O) = x I
inc (x I) = (inc x) O
_↑ : Bin → ℕ
⟨⟩ ↑ = 0
(x O) ↑ = x ↑ + x ↑
(x I) ↑ = suc (x ↑ + x ↑)
prop : ∀ {b} → (inc b) ↑ ≡ suc (b ↑)
prop {⟨⟩} = refl
prop {b O} = refl
prop {b I} rewrite prop {b} | +-suc (b ↑) (b ↑) = refl
_↓ : ℕ → Bin
zero ↓ = ⟨⟩ O
suc n ↓ = inc (n ↓)
↑↓ : ∀ {n} → (n ↓) ↑ ≡ n
↑↓ {zero} = refl
↑↓ {suc n} rewrite prop {n ↓} | ↑↓ {n} = refl
-- One b -> b start with ⟨⟩ I
data One : Bin → Set where
first : One (⟨⟩ I)
nextO : ∀ { b : Bin }
→ One b
------------
→ One (b O)
nextI : ∀ { b : Bin }
→ One b
------------
→ One (b I)
-- Can i.e Canonical representing binary numbers without extras leading zeros after ⟨⟩. For e.g ⟨⟩ O O I I and ⟨⟩ I I both represents binary form of number 3 but only ⟨⟩ I I is the canonical
data Can : Bin → Set where
startWithZero : Can (⟨⟩ O)
startWithOne : ∀ {b : Bin }
→ One b
------------
→ Can b
-- If m ≤ n then m ≤ (n + 1)
≤-sucʳ : ∀ {m n : ℕ }
→ m ≤ n
-----------
→ m ≤ suc n
≤-sucʳ z≤n = z≤n
≤-sucʳ (s≤s m≤n) = s≤s (≤-sucʳ m≤n)
-- If m ≤ n then m ≤ (n + p)
≤-addʳ : ∀ (m n p : ℕ)
→ m ≤ n
--------
→ m ≤ n + p
≤-addʳ m n zero m≤n rewrite +-comm n zero = m≤n
≤-addʳ m n (suc p) m≤n rewrite +-comm n (suc p) | +-comm p n = ≤-sucʳ (≤-addʳ m n p m≤n)
-- If a natural number n has eqivalent binary form (⟨⟩ I b) then 1 ≤ n
1-≤-oneb : ∀ { b : Bin }
→ One b
---------
→ suc zero ≤ b ↑
1-≤-oneb first = s≤s z≤n
1-≤-oneb {b O} (nextO oneb) = ≤-addʳ 1 ((b ↑)) ((b ↑)) (1-≤-oneb oneb)
1-≤-oneb {b I} (nextI oneb) = ≤-sucʳ (≤-addʳ 1 ((b ↑)) ((b ↑)) (1-≤-oneb oneb))
-- If 0 ≤ (n + 1) then 1 ≤ n
0-≤-suc : ∀ (n : ℕ)
→ 0 ≤ suc n
-----------
→ 1 ≤ suc n
0-≤-suc n z≤n = s≤s z≤n
-- If 1 ≤ n and binary form of n is b then binary form of (n + n) using ↓ is b O
↓-over-+ : ∀ (n : ℕ)
→ 1 ≤ n
-----------------------
→ (n + n) ↓ ≡ (n ↓) O
↓-over-+ (suc zero) s≤n = refl
↓-over-+ (suc (suc n)) (s≤s s≤n) = begin
(suc (suc n) + (suc (suc n))) ↓
≡⟨⟩
inc (( suc n + (suc (suc n))) ↓)
≡⟨ cong (inc) (cong (_↓) (+-comm (suc n) (suc (suc n)))) ⟩
inc (inc ((suc n + suc n) ↓))
≡⟨ cong (inc) (cong inc (↓-over-+ (suc n) (0-≤-suc n s≤n))) ⟩
refl
-- For all binary numbers that are canonical, ↑↓ is identity (returns same b)
↑↓-canb : ∀ ( b : Bin )
→ Can b
--------------
→ (b ↑) ↓ ≡ b
↑↓-canb _ startWithZero = refl
↑↓-canb _ (startWithOne first) = refl
↑↓-canb (b O) (startWithOne (nextO x)) rewrite ↓-over-+ (b ↑) (1-≤-oneb x) | ↑↓-canb b (startWithOne x) = refl
↑↓-canb (b I) (startWithOne (nextI x)) rewrite ↓-over-+ (b ↑) (1-≤-oneb x) | ↑↓-canb b (startWithOne x) = refl

How to implement a typed tagless interpreter?

[1] describes a very interesting approach to define a language syntax and semantics. The idea is to use classes instead of ADTs to describe a syntax:
class ExpSYM =
fixes lit :: "int ⇒ 'a"
and neg :: "'a ⇒ 'a"
and add :: "'a ⇒ 'a ⇒ 'a"
Semantics is described using a class instantiation for a some value domain (int):
instantiation int :: ExpSYM
begin
definition "lit_int (n :: int) ≡ n"
definition "neg_int (e :: int) ≡ -e"
definition "add_int (e1 :: int) (e2) ≡ e1 + e2"
instance ..
end
definition eval :: "int ⇒ int" where
"eval ≡ id"
Here is some examples:
term "add (lit 1) (lit 2)"
term "eval (add (lit 1) (lit 2))"
value "eval (add (lit 1) (lit 2))"
The approach allows to extend a language easily:
class MulSYM =
fixes mul :: "'a ⇒ 'a ⇒ 'a"
instantiation int :: MulSYM
begin
definition "mul_int (e1 :: int) (e2) ≡ e1 * e2"
instance ..
end
term "eval (mul (add (lit 1) (lit 2)) (lit 5))"
value "eval (mul (add (lit 1) (lit 2)) (lit 5))"
Also the approach allows to define language semantics without value tags and pattern matching:
datatype val = BoolVal bool | IntVal int | StringVal string
The problem is that I can't implement the following Haskell example from [2] in Isabelle HOL:
class Symantics repr where
int :: Int → repr Int
add :: repr Int → repr Int → repr Int
lam :: (repr a → repr b) → repr (a → b)
app :: repr (a → b) → repr a → repr b
Author calls it symantics, because
the class declaration defines the syntax of the embedded language (its
expression forms); class instances define interpretations, or the
semantics.
repr is a parameter representing a type instance of the class. This type is parametric. It can take Int as parameter (repr Int), or it can take an arrow type (repr (a → b)).
Here is an example of language expressions with different types:
th1 = add (int 1) (int 2)
−− th1 :: (Symantics repr) ⇒ repr Int
th2 = lam (\x → add x x)
−− th2 :: (Symantics repr) ⇒ repr (Int → Int)
th3 = lam (\x → add (app x (int 1)) (int 2))
−− th3 :: (Symantics repr) ⇒ repr ((Int → Int) → Int)
Here is the interpreter of the language:
newtype R a = R{unR :: a}
instance Symantics R where
int x = R x
add e1 e2 = R $ unR e1 + unR e2
lam f = R $ unR ◦ f ◦ R
app e1 e2 = R $ (unR e1) (unR e2)
−− eval :: R a → a
eval e = unR e
How to implement an analogous interpreter in Isabelle HOL? It seems that classes and locales aren't applicable here.
There is also a similar tagless interpreter based on generalized algebraic data types in the lecture notes [3]:
data Exp env t where
B :: Bool → Exp env Bool
V :: Var env t → Exp env t
L :: Exp (a,env) b → Exp env (a → b)
A :: Exp env (a → b) → Exp env a → Exp env b
data Var env t where
VZ :: Var (t, env) t
VS :: Var env t → Var (a, env) t
eval :: env → Exp env t → t
eval env (V v) = lookp v env
eval env (B b) = b
eval env (L e) = \x → eval (x, env) e
eval env (A e1 e2) = (eval env e1) (eval env e2)
Could you suggest how to implement these two tagless interpreters in Isabelle HOL?
[1] Oleg Kiselyov. Typed Tagless Final Interpreters
[2] --//--. Section 3.4 Tagless final embedding with higher-order abstract syntax. Page 29
[3] --//--, Section 3.2 Tagless, initial and final embeddings. Pages 22-23

Formulating proof for assignment

Consider the following code from an assignment. The aim here is to prove that transactions on accounts are commutative. From what i understand is there are two accounts e1{cash 10} and e2{cash 20}. So if i make a transaction on e1 by giving 10 and then on e2 by giving 10 then and then i do it in the reverse order then at the end the account state is the same. For this i have to prove the the account states in between are equivalent.
like the account state [e1{10} e2{20}]->[e1{0} e2{20}]->[e1{0} e2{10}] and [e1{10} e2{20}]->[e1{10} e2{10}]->[e1{0} e2{10}] i-e the states in between lead to the same state. Is my thinking correct? How do i formulate this? This looked trivial at first glance to me but is not that easy.
module Acc where
open import Data.Nat hiding (_≟_; _+_; _≤_)
open import Data.Integer hiding (_≟_; suc)
open import Data.String
open import Data.Product
open import Relation.Nullary
open import Relation.Nullary.Decidable
open import Relation.Binary.PropositionalEquality
-- Trivial example of an EDSL inspired by
-- http://www.lpenz.org/articles/hedsl-sharedexpenses/
-- We have n people who go on a trip
-- they pay for things
-- they give each other money
-- at the end we want to have the balance on each account
-- Syntax
infixr 10 _•_
infixr 10 _and_
infix 20 _⇒_
data Person : Set where
P : String → Person
data Exp : Set where
_⇒_ : Person → ℕ → Exp
_[_]⇒_ : Person → ℕ → Person → Exp
_and_ : Exp → Exp → Exp
data Accounts : Set where
□ : Accounts
_,_ : (String × ℤ) → Accounts → Accounts
data _∈ᵣ_ : (String × ℤ) → Accounts → Set where
hereᵣ : ∀ {ρ s v} → (s , v) ∈ᵣ ((s , v) , ρ)
skipᵣ : ∀ {ρ s v s' v'} →
{α : False (s ≟ s')} → (s , v) ∈ᵣ ρ → (s , v) ∈ᵣ ((s' , v') , ρ)
update : Accounts → String → ℤ → Accounts
update □ s amount = (s , amount) , □
update ((s₁ , amount₁) , accounts) s₂ amount₂ with (s₁ ≟ s₂)
... | yes _ = (s₁ , (amount₁ + amount₂)) , accounts
... | no _ = (s₁ , amount₁) , update accounts s₂ amount₂
data account : Exp → Accounts → Accounts → Set where
spend : ∀ {s n σ} → account (P s ⇒ (suc n)) σ (update σ s -[1+ n ])
give : ∀ {s₁ s₂ n σ} → account (P s₁ [ suc n ]⇒ P s₂) σ
(update (update σ s₁ -[1+ n ]) s₂ (+ (suc n)))
_•_ : ∀ {e₁ e₂ σ₁ σ₂ σ₃} →
account e₁ σ₁ σ₂ → account e₂ σ₂ σ₃ → account (e₁ and e₂) σ₁ σ₃
andComm : ∀ {σ σ' σ'' e₁ e₂} → account (e₁ and e₂) σ σ' →
account (e₂ and e₁) σ σ'' → σ' ≡ σ''
andComm (a₁ • a) (b • b₁) = {!!}

Termination-checking of function over a trie

I'm having difficulty convincing Agda to termination-check the function fmap below and similar functions defined recursively over the structure of a Trie. A Trie is a trie whose domain is a Type, an object-level type formed from unit, products and fixed points (I've omitted coproducts to keep the code minimal). The problem seems to relate to a type-level substitution I use in the definition of Trie. (The expression const (μₜ τ) * τ means apply the substitution const (μₜ τ) to the type τ.)
module Temp where
open import Data.Unit
open import Category.Functor
open import Function
open import Level
open import Relation.Binary
-- A context is just a snoc-list.
data Cxt {𝒂} (A : Set 𝒂) : Set 𝒂 where
ε : Cxt A
_∷ᵣ_ : Cxt A → A → Cxt A
-- Context membership.
data _∈_ {𝒂} {A : Set 𝒂} (a : A) : Cxt A → Set 𝒂 where
here : ∀ {Δ} → a ∈ Δ ∷ᵣ a
there : ∀ {Δ a′} → a ∈ Δ → a ∈ Δ ∷ᵣ a′
infix 3 _∈_
-- Well-formed types, using de Bruijn indices.
data _⊦ (Δ : Cxt ⊤) : Set where
nat : Δ ⊦
𝟏 : Δ ⊦
var : _ ∈ Δ → Δ ⊦
_+_ _⨰_ : Δ ⊦ → Δ ⊦ → Δ ⊦
μ : Δ ∷ᵣ _ ⊦ → Δ ⊦
infix 3 _⊦
-- A closed type.
Type : Set
Type = ε ⊦
-- Type-level substitutions and renamings.
Sub Ren : Rel (Cxt ⊤) zero
Sub Δ Δ′ = _ ∈ Δ → Δ′ ⊦
Ren Δ Δ′ = ∀ {x} → x ∈ Δ → x ∈ Δ′
-- Renaming extension.
extendᵣ : ∀ {Δ Δ′} → Ren Δ Δ′ → Ren (Δ ∷ᵣ _) (Δ′ ∷ᵣ _)
extendᵣ ρ here = here
extendᵣ ρ (there x) = there (ρ x)
-- Lift a type renaming to a type.
_*ᵣ_ : ∀ {Δ Δ′} → Ren Δ Δ′ → Δ ⊦ → Δ′ ⊦
_ *ᵣ nat = nat
_ *ᵣ 𝟏 = 𝟏
ρ *ᵣ (var x) = var (ρ x)
ρ *ᵣ (τ₁ + τ₂) = (ρ *ᵣ τ₁) + (ρ *ᵣ τ₂)
ρ *ᵣ (τ₁ ⨰ τ₂) = (ρ *ᵣ τ₁) ⨰ (ρ *ᵣ τ₂)
ρ *ᵣ (μ τ) = μ (extendᵣ ρ *ᵣ τ)
-- Substitution extension.
extend : ∀ {Δ Δ′} → Sub Δ Δ′ → Sub (Δ ∷ᵣ _) (Δ′ ∷ᵣ _)
extend θ here = var here
extend θ (there x) = there *ᵣ (θ x)
-- Lift a type substitution to a type.
_*_ : ∀ {Δ Δ′} → Sub Δ Δ′ → Δ ⊦ → Δ′ ⊦
θ * nat = nat
θ * 𝟏 = 𝟏
θ * var x = θ x
θ * (τ₁ + τ₂) = (θ * τ₁) + (θ * τ₂)
θ * (τ₁ ⨰ τ₂) = (θ * τ₁) ⨰ (θ * τ₂)
θ * μ τ = μ (extend θ * τ)
data Trie {𝒂} (A : Set 𝒂) : Type → Set 𝒂 where
〈〉 : A → 𝟏 ▷ A
〔_,_〕 : ∀ {τ₁ τ₂} → τ₁ ▷ A → τ₂ ▷ A → τ₁ + τ₂ ▷ A
↑_ : ∀ {τ₁ τ₂} → τ₁ ▷ τ₂ ▷ A → τ₁ ⨰ τ₂ ▷ A
roll : ∀ {τ} → (const (μ τ) * τ) ▷ A → μ τ ▷ A
infixr 5 Trie
syntax Trie A τ = τ ▷ A
{-# NO_TERMINATION_CHECK #-}
fmap : ∀ {a} {A B : Set a} {τ} → (A → B) → τ ▷ A → τ ▷ B
fmap f (〈〉 x) = 〈〉 (f x)
fmap f 〔 σ₁ , σ₂ 〕 = 〔 fmap f σ₁ , fmap f σ₂ 〕
fmap f (↑ σ) = ↑ (fmap (fmap f) σ)
fmap f (roll σ) = roll (fmap f σ)
It would seem that fmap recurses into a strictly smaller argument in each case; certainly the product case is fine if I remove recursive types. On the other hand, the definition handles recursive types fine if I remove products.
What's the simplest way to proceed here? The inline/fuse trick does not look particularly applicable, but maybe it is. Or should I be looking for another way to deal with the substitution in the definition of Trie?
The inline/fuse trick can be applied in (perhaps) surprising way. This trick is suited for problems of this sort:
data Trie (A : Set) : Set where
nil : Trie A
node : A → List (Trie A) → Trie A
map-trie : {A B : Set} → (A → B) → Trie A → Trie B
map-trie f nil = nil
map-trie f (node x xs) = node (f x) (map (map-trie f) xs)
This function is structurally recursive, but in a hidden way. map just applies map-trie f to the elements of xs, so map-trie gets applied to smaller (sub-)tries. But Agda doesn't look through the definition of map to see that it doesn't do anything funky. So we must apply the inline/fuse trick to get it past termination checker:
map-trie : {A B : Set} → (A → B) → Trie A → Trie B
map-trie f nil = nil
map-trie {A} {B} f (node x xs) = node (f x) (map′ xs)
where
map′ : List (Trie A) → List (Trie B)
map′ [] = []
map′ (x ∷ xs) = map-trie f x ∷ map′ xs
Your fmap function shares the same structure, you map a lifted function of some sort. But what to inline? If we follow the example above, we should inline fmap itself. This looks and feels a bit strange, but indeed, it works:
fmap fmap′ : ∀ {a} {A B : Set a} {τ} → (A → B) → τ ▷ A → τ ▷ B
fmap f (〈〉 x) = 〈〉 (f x)
fmap f 〔 σ₁ , σ₂ 〕 = 〔 fmap f σ₁ , fmap f σ₂ 〕
fmap f (↑ σ) = ↑ (fmap (fmap′ f) σ)
fmap f (roll σ) = roll (fmap f σ)
fmap′ f (〈〉 x) = 〈〉 (f x)
fmap′ f 〔 σ₁ , σ₂ 〕 = 〔 fmap′ f σ₁ , fmap′ f σ₂ 〕
fmap′ f (↑ σ) = ↑ (fmap′ (fmap f) σ)
fmap′ f (roll σ) = roll (fmap′ f σ)
There's another technique you can apply: it's called sized types. Instead of relying on the compiler to figure out when somethig is or is not structurally recursive, you instead specify it directly. However, you have to index your data types by a Size type, so this approach is fairly intrusive and cannot be applied to already existing types, but I think it is worth mentioning.
In its simplest form, sized type behaves as a type indexed by a natural number. This index specifies the upper bound of structural size. You can think of this as an upper bound for the height of a tree (given that the data type is an F-branching tree for some functor F). Sized version of List looks almost like a Vec, for example:
data SizedList (A : Set) : ℕ → Set where
[] : ∀ {n} → SizedList A n
_∷_ : ∀ {n} → A → SizedList A n → SizedList A (suc n)
But sized types add few features that make them easier to use. You have a constant ∞ for the case when you don't care about the size. suc is called ↑ and Agda implements few rules, such as ↑ ∞ = ∞.
Let's rewrite the Trie example to use sized types. We need a pragma at the top of the file and one import:
{-# OPTIONS --sized-types #-}
open import Size
And here's the modified data type:
data Trie (A : Set) : {i : Size} → Set where
nil : ∀ {i} → Trie A {↑ i}
node : ∀ {i} → A → List (Trie A {i}) → Trie A {↑ i}
If you leave the map-trie function as is, the termination checker is still going to complain. That's because when you don't specify any size, Agda will fill in infinity (i.e. don't-care value) and we are back at the beginning.
However, we can mark map-trie as size-preserving:
map-trie : ∀ {i A B} → (A → B) → Trie A {i} → Trie B {i}
map-trie f nil = nil
map-trie f (node x xs) = node (f x) (map (map-trie f) xs)
So, if you give it a Trie bounded by i, it will give you another Trie bounded by i as well. So map-trie can never make the Trie larger, only equally large or smaller. This is enough for the termination checker to figure out that map (map-trie f) xs is okay.
This technique can also be applied to your Trie:
open import Size
renaming (↑_ to ^_)
data Trie {𝒂} (A : Set 𝒂) : {i : Size} → Type → Set 𝒂 where
〈〉 : ∀ {i} → A →
Trie A {^ i} 𝟏
〔_,_〕 : ∀ {i τ₁ τ₂} → Trie A {i} τ₁ → Trie A {i} τ₂ →
Trie A {^ i} (τ₁ + τ₂)
↑_ : ∀ {i τ₁ τ₂} → Trie (Trie A {i} τ₂) {i} τ₁ →
Trie A {^ i} (τ₁ ⨰ τ₂)
roll : ∀ {i τ} → Trie A {i} (const (μ τ) * τ) →
Trie A {^ i} (μ τ)
infixr 5 Trie
syntax Trie A τ = τ ▷ A
fmap : ∀ {i 𝒂} {A B : Set 𝒂} {τ} → (A → B) → Trie A {i} τ → Trie B {i} τ
fmap f (〈〉 x) = 〈〉 (f x)
fmap f 〔 σ₁ , σ₂ 〕 = 〔 fmap f σ₁ , fmap f σ₂ 〕
fmap f (↑ σ) = ↑ fmap (fmap f) σ
fmap f (roll σ) = roll (fmap f σ)

Assisting Agda's termination checker

Suppose we define a function
f : N \to N
f 0 = 0
f (s n) = f (n/2) -- this / operator is implemented as floored division.
Agda will paint f in salmon because it cannot tell if n/2 is smaller than n. I don't know how to tell Agda's termination checker anything. I see in the standard library they have a floored division by 2 and a proof that n/2 < n. However, I still fail to see how to get the termination checker to realize that recursion has been made on a smaller subproblem.
Agda's termination checker only checks for structural recursion (i.e. calls that happen on structurally smaller arguments) and there's no way to establish that certain relation (such as _<_) implies that one of the arguments is structurally smaller.
Digression: Similar problem happens with positivity checker. Consider the standard fix-point data type:
data μ_ (F : Set → Set) : Set where
fix : F (μ F) → μ F
Agda rejects this because F may not be positive in its first argument. But we cannot restrict μ to only take positive type functions, or show that some particular type function is positive.
How do we normally show that a recursive functions terminates? For natural numbers, this is the fact that if the recursive call happens on strictly smaller number, we eventually have to reach zero and the recursion stops; for lists the same holds for its length; for sets we could use the strict subset relation; and so on. Notice that "strictly smaller number" doesn't work for integers.
The property that all these relations share is called well-foundedness. Informally speaking, a relation is well-founded if it doesn't have any infinite descending chains. For example, < on natural numbers is well founded, because for any number n:
n > n - 1 > ... > 2 > 1 > 0
That is, the length of such chain is limited by n + 1.
≤ on natural numbers, however, is not well-founded:
n ≥ n ≥ ... ≥ n ≥ ...
And neither is < on integers:
n > n - 1 > ... > 1 > 0 > -1 > ...
Does this help us? It turns out we can encode what it means for a relation to be well-founded in Agda and then use it to implement your function.
For simplicity, I'm going to bake the _<_ relation into the data type. First of all, we must define what it means for a number to be accessible: n is accessible if all m such that m < n are also accessible. This of course stops at n = 0, because there are no m so that m < 0 and this statement holds trivially.
data Acc (n : ℕ) : Set where
acc : (∀ m → m < n → Acc m) → Acc n
Now, if we can show that all natural numbers are accessible, then we showed that < is well-founded. Why is that so? There must be a finite number of the acc constructors (i.e. no infinite descending chain) because Agda won't let us write infinite recursion. Now, it might seem as if we just pushed the problem back one step further, but writing the well-foundedness proof is actually structurally recursive!
So, with that in mind, here's the definition of < being well-founded:
WF : Set
WF = ∀ n → Acc n
And the well-foundedness proof:
<-wf : WF
<-wf n = acc (go n)
where
go : ∀ n m → m < n → Acc m
go zero m ()
go (suc n) zero _ = acc λ _ ()
go (suc n) (suc m) (s≤s m<n) = acc λ o o<sm → go n o (trans o<sm m<n)
Notice that go is nicely structurally recursive. trans can be imported like this:
open import Data.Nat
open import Relation.Binary
open DecTotalOrder decTotalOrder
using (trans)
Next, we need a proof that ⌊ n /2⌋ ≤ n:
/2-less : ∀ n → ⌊ n /2⌋ ≤ n
/2-less zero = z≤n
/2-less (suc zero) = z≤n
/2-less (suc (suc n)) = s≤s (trans (/2-less n) (right _))
where
right : ∀ n → n ≤ suc n
right zero = z≤n
right (suc n) = s≤s (right n)
And finally, we can write your f function. Notice how it suddenly becomes structurally recursive thanks to Acc: the recursive calls happen on arguments with one acc constructor peeled off.
f : ℕ → ℕ
f n = go _ (<-wf n)
where
go : ∀ n → Acc n → ℕ
go zero _ = 0
go (suc n) (acc a) = go ⌊ n /2⌋ (a _ (s≤s (/2-less _)))
Now, having to work directly with Acc isn't very nice. And that's where Dominique's answer comes in. All this stuff I've written here has already been done in the standard library. It is more general (the Acc data type is actually parametrized over the relation) and it allows you to just use <-rec without having to worry about Acc.
Taking a more closer look, we are actually pretty close to the generic solution. Let's see what we get when we parametrize over the relation. For simplicity I'm not dealing with universe polymorphism.
A relation on A is just a function taking two As and returning Set (we could call it binary predicate):
Rel : Set → Set₁
Rel A = A → A → Set
We can easily generalize Acc by changing the hardcoded _<_ : ℕ → ℕ → Set to an arbitrary relation over some type A:
data Acc {A} (_<_ : Rel A) (x : A) : Set where
acc : (∀ y → y < x → Acc _<_ y) → Acc _<_ x
The definition of well-foundedness changes accordingly:
WellFounded : ∀ {A} → Rel A → Set
WellFounded _<_ = ∀ x → Acc _<_ x
Now, since Acc is an inductive data type like any other, we should be able to write its eliminator. For inductive types, this is a fold (much like foldr is eliminator for lists) - we tell the eliminator what to do with each constructor case and the eliminator applies this to the whole structure.
In this case, we'll do just fine with the simple variant:
foldAccSimple : ∀ {A} {_<_ : Rel A} {R : Set} →
(∀ x → (∀ y → y < x → R) → R) →
∀ z → Acc _<_ z → R
foldAccSimple {R = R} acc′ = go
where
go : ∀ z → Acc _ z → R
go z (acc a) = acc′ z λ y y<z → go y (a y y<z)
If we know that _<_ is well-founded, we can skip the Acc _<_ z argument completly, so let's write small convenience wrapper:
recSimple : ∀ {A} {_<_ : Rel A} → WellFounded _<_ → {R : Set} →
(∀ x → (∀ y → y < x → R) → R) →
A → R
recSimple wf acc′ z = foldAccSimple acc′ z (wf z)
And finally:
<-wf : WellFounded _<_
<-wf = {- same definition -}
<-rec = recSimple <-wf
f : ℕ → ℕ
f = <-rec go
where
go : ∀ n → (∀ m → m < n → ℕ) → ℕ
go zero _ = 0
go (suc n) r = r ⌊ n /2⌋ (s≤s (/2-less _))
And indeed, this looks (and works) almost like the one in the standard library!
Here's the fully dependent version in case you are wondering:
foldAcc : ∀ {A} {_<_ : Rel A} (P : A → Set) →
(∀ x → (∀ y → y < x → P y) → P x) →
∀ z → Acc _<_ z → P z
foldAcc P acc′ = go
where
go : ∀ z → Acc _ z → P z
go _ (acc a) = acc′ _ λ _ y<z → go _ (a _ y<z)
rec : ∀ {A} {_<_ : Rel A} → WellFounded _<_ →
(P : A → Set) → (∀ x → (∀ y → y < x → P y) → P x) →
∀ z → P z
rec wf P acc′ z = foldAcc P acc′ _ (wf z)
I would like to offer a slightly different answer than the ones given above. In particular, I want to suggest that instead of trying to somehow convince the termination checker that actually, no, this recursion is perfectly fine, we should instead try to reify the well-founded-ness so that the recursion is manifestly fine in virtue of being structural.
The idea here is that the problem comes from being unable to see that n / 2 is somehow a "part" of n. Structural recursion wants to break a thing into its immediate parts, but the way that n / 2 is a "part" of n is that we drop every other suc. But it's not obvious up front how many to drop, we have to look around and try to line things up. What would be nice is if we had some type that had constructors for "multiple" sucs.
To make the problem slightly more interesting, let's instead try to define the function that behaves like
f : ℕ → ℕ
f 0 = 0
f (suc n) = 1 + (f (n / 2))
that is to say, it should be the case that
f n = ⌈ log₂ (n + 1) ⌉
Now naturally the above definition won't work, for the same reasons your f won't. But let's pretend that it did, and let's explore the "path", so to speak, that the argument would take through the natural numbers. Suppose we look at n = 8:
f 8 = 1 + f 4 = 1 + 1 + f 2 = 1 + 1 + 1 + f 1 = 1 + 1 + 1 + 1 + f 0 = 1 + 1 + 1 + 1 + 0 = 4
so the "path" is 8 -> 4 -> 2 -> 1 -> 0. What about, say, 11?
f 11 = 1 + f 5 = 1 + 1 + f 2 = ... = 4
so the "path" is 11 -> 5 -> 2 -> 1 -> 0.
Well naturally what's going on here is that at each step we're either dividing by 2, or subtracting one and dividing by 2. Every naturally number greater than 0 can be decomposed uniquely in this fashion. If it's even, divide by two and proceed, if it's odd, subtract one and divide by two and proceed.
So now we can see exactly what our data type should look like. We need a type that has a constructor that means "twice as many suc's" and another that means "twice as many suc's plus one", as well as of course a constructor that means "zero sucs":
data Decomp : ℕ → Set where
zero : Decomp zero
2*_ : ∀ {n} → Decomp n → Decomp (n * 2)
2*_+1 : ∀ {n} → Decomp n → Decomp (suc (n * 2))
We can now define the function that decomposes a natural number into the Decomp that corresponds to it:
decomp : (n : ℕ) → Decomp n
decomp zero = zero
decomp (suc n) = decomp n +1
It helps to define +1 for Decomps:
_+1 : {n : ℕ} → Decomp n → Decomp (suc n)
zero +1 = 2* zero +1
(2* d) +1 = 2* d +1
(2* d +1) +1 = 2* (d +1)
Given a Decomp, we can flatten it down into a natural number that ignores the distinctions between 2*_ and 2*_+1:
flatten : {n : ℕ} → Decomp n → ℕ
flatten zero = zero
flatten (2* p) = suc (flatten p)
flatten (2* p +1 = suc (flatten p)
And now it's trivial to define f:
f : ℕ → ℕ
f n = flatten (decomp n)
This happily passes the termination checker with no trouble, because we're never actually recursing on the problematic n / 2. Instead, we convert the number into a format that directly represents its path through the number space in a structurally recursive way.
Edit It occurred to me only a little while ago that Decomp is a little-endian representation of binary numbers. 2*_ is "append 0 to the end/shift left 1 bit" and 2*_+1 is "append 1 to the end/shift left 1 bit and add one". So the above code is really about showing that binary numbers are structurally recursive wrt dividing by 2, which they ought to be! That makes it much easier to understand, I think, but I don't want to change what I wrote already, so we could instead do some renaming here: Decomp ~> Binary, 2*_ ~> _,zero, 2*_+1 ~> _,one, decomp ~> natToBin, flatten ~> countBits.
After accepting Vitus' answer, I discovered a different way to accomplish the goal of proving a function terminates in Agda, namely using "sized types." I am providing my answer here because it seems acceptable, and also for critique of any weak points of this answer.
Sized types are described:
http://arxiv.org/pdf/1012.4896.pdf
They are implemented in Agda, not only MiniAgda; see here: http://www2.tcs.ifi.lmu.de/~abel/talkAIM2008Sendai.pdf.
The idea is to augment the data type with a size that allows the typechecker to more easily prove termination. Size is defined in the standard library.
open import Size
We define sized natural numbers:
data Nat : {i : Size} \to Set where
zero : {i : Size} \to Nat {\up i}
succ : {i : Size} \to Nat {i} \to Nat {\up i}
Next, we define predecessor and subtraction (monus):
pred : {i : Size} → Nat {i} → Nat {i}
pred .{↑ i} (zero {i}) = zero {i}
pred .{↑ i} (succ {i} n) = n
sub : {i : Size} → Nat {i} → Nat {∞} → Nat {i}
sub .{↑ i} (zero {i}) n = zero {i}
sub .{↑ i} (succ {i} m) zero = succ {i} m
sub .{↑ i} (succ {i} m) (succ n) = sub {i} m n
Now, we may define division via Euclid's algorithm:
div : {i : Size} → Nat {i} → Nat → Nat {i}
div .{↑ i} (zero {i}) n = zero {i}
div .{↑ i} (succ {i} m) n = succ {i} (div {i} (sub {i} m n) n)
data ⊥ : Set where
record ⊤ : Set where
notZero : Nat → Set
notZero zero = ⊥
notZero _ = ⊤
We give division for nonzero denominators.
If the denominator is nonzero, then it is of the form, b+1. We then do
divPos a (b+1) = div a b
Since div a b returns ceiling (a/(b+1)).
divPos : {i : Size} → Nat {i} → (m : Nat) → (notZero m) → Nat {i}
divPos a (succ b) p = div a b
divPos a zero ()
As auxiliary:
div2 : {i : Size} → Nat {i} → Nat {i}
div2 n = divPos n (succ (succ zero)) (record {})
Now we can define a divide and conquer method for computing the n-th Fibonacci number.
fibd : {i : Size} → Nat {i} → Nat
fibd zero = zero
fibd (succ zero) = succ zero
fibd (succ (succ zero)) = succ zero
fibd (succ n) with even (succ n)
fibd .{↑ i} (succ {i} n) | true =
let
-- When m=n+1, the input, is even, we set k = m/2
-- Note, ceil(m/2) = ceil(n/2)
k = div2 {i} n
fib[k-1] = fibd {i} (pred {i} k)
fib[k] = fibd {i} k
fib[k+1] = fib[k-1] + fib[k]
in
(fib[k+1] * fib[k]) + (fib[k] * fib[k-1])
fibd .{↑ i} (succ {i} n) | false =
let
-- When m=n+1, the input, is odd, we set k = n/2 = (m-1)/2.
k = div2 {i} n
fib[k-1] = fibd {i} (pred {i} k)
fib[k] = fibd {i} k
fib[k+1] = fib[k-1] + fib[k]
in
(fib[k+1] * fib[k+1]) + (fib[k] * fib[k])
You cannot do this directly: Agda's termination checker only considers recursion ok on arguments that are syntactically smaller. However, the Agda standard library provides a few modules for proving termination using a well-founded order between the arguments of the functions. The standard order on natural numbers is such an order and can be used here.
Using the code in Induction.*, you can write your function as follows:
open import Data.Nat
open import Induction.WellFounded
open import Induction.Nat
s≤′s : ∀ {n m} → n ≤′ m → suc n ≤′ suc m
s≤′s ≤′-refl = ≤′-refl
s≤′s (≤′-step lt) = ≤′-step (s≤′s lt)
proof : ∀ n → ⌊ n /2⌋ ≤′ n
proof 0 = ≤′-refl
proof 1 = ≤′-step (proof zero)
proof (suc (suc n)) = ≤′-step (s≤′s (proof n))
f : ℕ → ℕ
f = <-rec (λ _ → ℕ) helper
where
helper : (n : ℕ) → (∀ y → y <′ n → ℕ) → ℕ
helper 0 rec = 0
helper (suc n) rec = rec ⌊ n /2⌋ (s≤′s (proof n))
I found an article with some explanation here. But there may be better references out there.
A similar question appeared on the Agda mailing-list a few weeks ago and the consensus seemed to be to inject the Data.Nat element into Data.Bin and then use structural recursion on this representation which is well-suited for the job at hand.
You can find the whole thread here : http://comments.gmane.org/gmane.comp.lang.agda/5690
You can avoid using well-founded recursion. Let's say you want a function, that applies ⌊_/2⌋ to a number, until it reaches 0, and collects the results. With the {-# TERMINATING #-} pragma it can be defined like this:
{-# TERMINATING #-}
⌊_/2⌋s : ℕ -> List ℕ
⌊_/2⌋s 0 = []
⌊_/2⌋s n = n ∷ ⌊ ⌊ n /2⌋ /2⌋s
The second clause is equivalent to
⌊_/2⌋s n = n ∷ ⌊ n ∸ (n ∸ ⌊ n /2⌋) /2⌋s
It's possible to make ⌊_/2⌋s structurally recursive by inlining this substraction:
⌊_/2⌋s : ℕ -> List ℕ
⌊_/2⌋s = go 0 where
go : ℕ -> ℕ -> List ℕ
go _ 0 = []
go 0 (suc n) = suc n ∷ go (n ∸ ⌈ n /2⌉) n
go (suc i) (suc n) = go i n
go (n ∸ ⌈ n /2⌉) n is a simplified version of go (suc n ∸ ⌊ suc n /2⌋ ∸ 1) n
Some tests:
test-5 : ⌊ 5 /2⌋s ≡ 5 ∷ 2 ∷ 1 ∷ []
test-5 = refl
test-25 : ⌊ 25 /2⌋s ≡ 25 ∷ 12 ∷ 6 ∷ 3 ∷ 1 ∷ []
test-25 = refl
Now let's say you want a function, that applies ⌊_/2⌋ to a number, until it reaches 0, and sums the results. It's simply
⌊_/2⌋sum : ℕ -> ℕ
⌊ n /2⌋sum = go ⌊ n /2⌋s where
go : List ℕ -> ℕ
go [] = 0
go (n ∷ ns) = n + go ns
So we can just run our recursion on a list, that contains values, produced by the ⌊_/2⌋s function.
More concise version is
⌊ n /2⌋sum = foldr _+_ 0 ⌊ n /2⌋s
And back to the well-foundness.
open import Function
open import Relation.Nullary
open import Relation.Binary
open import Induction.WellFounded
open import Induction.Nat
calls : ∀ {a b ℓ} {A : Set a} {_<_ : Rel A ℓ} {guarded : A -> Set b}
-> (f : A -> A)
-> Well-founded _<_
-> (∀ {x} -> guarded x -> f x < x)
-> (∀ x -> Dec (guarded x))
-> A
-> List A
calls {A = A} {_<_} f wf smaller dec-guarded x = go (wf x) where
go : ∀ {x} -> Acc _<_ x -> List A
go {x} (acc r) with dec-guarded x
... | no _ = []
... | yes g = x ∷ go (r (f x) (smaller g))
This function does the same as the ⌊_/2⌋s function, i.e. produces values for recursive calls, but for any function, that satisfies certain conditions.
Look at the definition of go. If x is not guarded, then return []. Otherwise prepend x and call go on f x (we could write go {x = f x} ...), which is structurally smaller.
We can redefine ⌊_/2⌋s in terms of calls:
⌊_/2⌋s : ℕ -> List ℕ
⌊_/2⌋s = calls {guarded = ?} ⌊_/2⌋ ? ? ?
⌊ n /2⌋s returns [], only when n is 0, so guarded = λ n -> n > 0.
Our well-founded relation is based on _<′_ and defined in the Induction.Nat module as <-well-founded.
So we have
⌊_/2⌋s = calls {guarded = λ n -> n > 0} ⌊_/2⌋ <-well-founded {!!} {!!}
The type of the next hole is {x : ℕ} → x > 0 → ⌊ x /2⌋ <′ x
We can easily prove this proposition:
open import Data.Nat.Properties
suc-⌊/2⌋-≤′ : ∀ n -> ⌊ suc n /2⌋ ≤′ n
suc-⌊/2⌋-≤′ 0 = ≤′-refl
suc-⌊/2⌋-≤′ (suc n) = s≤′s (⌊n/2⌋≤′n n)
>0-⌊/2⌋-<′ : ∀ {n} -> n > 0 -> ⌊ n /2⌋ <′ n
>0-⌊/2⌋-<′ {suc n} (s≤s z≤n) = s≤′s (suc-⌊/2⌋-≤′ n)
The type of the last hole is (x : ℕ) → Dec (x > 0), we can fill it by _≤?_ 1.
And the final definition is
⌊_/2⌋s : ℕ -> List ℕ
⌊_/2⌋s = calls ⌊_/2⌋ <-well-founded >0-⌊/2⌋-<′ (_≤?_ 1)
Now you can recurse on a list, produced by ⌊_/2⌋s, without any termination issues.
I encountered this sort of problem when trying to write a quick sort function in Agda.
While other answers seem to explain the problem and solutions more generally, coming from a CS background, I think the following wording would be more accessible for certain readers:
The problem of working with the Agda termination checker comes down to how we can internalize the termination checking process.
Suppose we want to define a function
func : Some-Recursively-Defined-Type → A
func non-recursive-case = some-a
func (recursive-case n) = some-other-func (func (f n)) (func (g n)) ...
In many of the cases, we the writers know f n and g n are going to be smaller than recursive-case n. Furthermore, it is not like the proofs for these being smaller are super difficult. The problem is more about how we can communicate this knowledge to Agda.
It turns out we can do this by adding a timer argument to the definition.
Timer : Type
Timer = Nat
measure : Some-Recursively-Defined-Type → Timer
-- this function returns an upper-bound of how many steps left to terminate
-- the estimate should be tight enough for the non-recursive cases that
-- given those estimates,
-- pattern matching on recursive cases is obviously impossible
measure = {! !}
func-aux :
(timer : Timer) -- the timer,
(actual-arguments : Some-Recursively-Defined-Type)
(timer-bounding : measure actual-arguments ≤ timer)
→ A
func-aux zero non-recursive-case prf = a
-- the prf should force args to only pattern match to the non-recursive cases
func-aux (succ t) non-recursive-case prf = a
func-aux (succ t) (recursive-case n) prf =
some-other-func (func-aux t (f n) prf') (func-aux t (g n) prf'') ... where
prf' : measure (f n) ≤ t
prf' = {! !}
prf'' : measure (g n) ≤ t
prf'' = {! !}
With these at hand, we can define the function we want as something like the following :
func : Some-Recursively-Defined-Type → A
func x with measure x
func x | n = func-aux n x (≤-is-reflexive n)
Caveat
I have not taken into account anything about whether the computation would be efficient.
While Timer type is not restricted to be Nat (but for all types with which we have a strong enough order relation to work with), I think it is pretty safe to say we don't gain much even if we consider such generality.

Resources