Zulip Chat Archive
Stream: new members
Topic: Something that doesn't reduce, again
Ilmārs Cīrulis (Sep 27 2025 at 22:45):
"Stole" the function merge from Init.Data.List.Sort.Basic and tried to use it for my purposes, but it doesn't reduce. Is there a way to modify it and make it reducible?
import Mathlib
def merge (xs ys : List Nat) : List Nat :=
match xs, ys with
| [], ys => ys
| xs, [] => xs
| x :: xs, y :: ys =>
if Nat.ble x y then
x :: merge xs (y :: ys)
else
y :: merge (x :: xs) ys
#reduce merge [1, 2, 3, 4] [2, 3, 4, 5]
#eval merge [1, 2, 3, 4] [2, 3, 4, 5]
Ilmārs Cīrulis (Sep 27 2025 at 22:47):
The original function is with @[irreducible] tag here, and I thought that maybe I can use it after copypasting the definition.
Aaron Liu (Sep 27 2025 at 22:54):
It's well founded recursion
Aaron Liu (Sep 27 2025 at 22:54):
which is always irreducible by default
Ilmārs Cīrulis (Sep 27 2025 at 22:55):
Ok, I will remember. Thank you!
Aaron Liu (Sep 27 2025 at 22:55):
You can see in src#List.merge that it isn't explicitly marked irreducible
Aaron Liu (Sep 27 2025 at 22:56):
There is probably a way to implement it in a way that it will reduce
Ilmārs Cīrulis (Sep 27 2025 at 23:01):
Yes, indeed.
I will try to find that way.
Aaron Liu (Sep 27 2025 at 23:02):
I can show you once I'm back at a keyboard
Aaron Liu (Sep 27 2025 at 23:20):
This is what I usually do to convert these termination by product lex kind of functions from well founded recursion into structural recursion
def merge (xs ys : List Nat) : List Nat :=
match xs with
| [] => ys
| x :: xs => go x xs ys fun ys => merge xs ys
where
go (x : Nat) (xs ys : List Nat) (k : List Nat → List Nat) :=
match ys with
| [] => x :: xs
| y :: ys =>
if x ≤ y then
x :: k (y :: ys)
else
y :: go x xs ys k
Ilmārs Cīrulis (Sep 27 2025 at 23:31):
Oh, interesting, thank you!
This is my try, which I clumsily threw together before looking at your solution.
import Mathlib
def merge_aux (W : Nat) : ∀ (L1 L2 : List Nat) (_ : L1.length + L2.length = W), List Nat :=
match W with
| 0 => fun _ _ _ => []
| w + 1 =>
fun L1 L2 H =>
match L1, L2 with
| [], _ => L2
| _, [] => L1
| x1 :: t1, x2 :: t2 =>
match Nat.ble x1 x2 with
| true => x1 :: merge_aux w t1 (x2 :: t2) (by simp at H; grind)
| false => x2 :: merge_aux w (x1 :: t1) t2 (by simp at H; grind)
def merge L1 L2 := merge_aux (L1.length + L2.length) L1 L2 rfl
#reduce merge [1, 2, 3, 4] [2, 3, 4, 5]
#eval merge [1, 2, 3, 4] [2, 3, 4, 5]
Aaron Liu (Sep 27 2025 at 23:32):
fuel?
Aaron Liu (Sep 27 2025 at 23:32):
I guess it's not really fuel
Aaron Liu (Sep 27 2025 at 23:33):
but in this case we have something better than fuel
Aaron Liu (Sep 27 2025 at 23:33):
since it's lexographic structural recursion we can split it up like this
Ilmārs Cīrulis (Sep 27 2025 at 23:37):
I will take your solution and use it, thank you!
Ilmārs Cīrulis (Sep 27 2025 at 23:41):
(and will study it, too, to be able to replicate it in similar situation next time)
Last updated: Dec 20 2025 at 21:32 UTC