Zulip Chat Archive
Stream: lean4
Topic: Lazy lists
Andrew Yang (Apr 28 2025 at 20:01):
What is the canonical way to get lazy lists?
Here's an example that I need: Suppose I have a l : List Nat
, and some (decidable but slow) predicate P : Nat -> Nat -> Bool
. I have a lean proof that P a b
is satisfied for some a b
in l
, and a paper proof that a
must be one of the first 10 elements of l
. How can I find any such a b
? If I had lazy list I could write ((l ×ˢ l).filter P).head sorry
which will only call P
times at most, but I have the impression that this is in lean.
Henrik Böving (Apr 28 2025 at 20:22):
You could just call List.find?
instead of filter
Andrew Yang (Apr 28 2025 at 20:50):
Thanks! I see. But I guess this is my bad in simplifying my example too much.
In my actual application I have such a function
def List.differences (l : List (List Nat)) : List Nat :=
(l.map fun li ↦ (li ×ˢ li).filterMap fun (i, j) ↦
if i < j then .some (j - i) else .none).flatten
And I want a performant implementation of l.differences.dedup.length == 1
if I know that each element will appear at most 10 times and that each (l[i]).Nodup
.
Andrew Yang (Apr 28 2025 at 20:59):
But side question: how does List.find?
avoid the problem?
Does (l ×ˢ l).find? P
not evaluate l ×ˢ l
first?
Henrik Böving (Apr 28 2025 at 21:02):
Sure but it won't evaluated P
that many times, if you also want to avoid that you could use a double for loop instead.
Andrew Yang (Apr 28 2025 at 21:15):
Using for loops for the application above, I now have
import Mathlib.Data.List.Defs
def List.differences (l : List (List Nat)) : List Nat :=
(l.map fun li ↦ (li ×ˢ li).filterMap fun (i, j) ↦
if i < j then .some (j - i) else .none).flatten
def List.differencesDedupLengthLEOne?
(l : List (List Nat)) : Bool := Id.run do
let mut thing := 0
let mut flag := false
for li in l do
for i in li do
for j in li do
if i >= j then continue
if not flag then
flag := true
thing := j - i
else if j - i == thing then
continue
else
return false
return true
theorem foo (l : List (List Nat)) :
l.differences.dedup.length <= 1 ↔ l.differencesDedupLengthLEOne? := sorry
Is this the intended way? I'll be sad if I am forced to do imperative programming in a FP language, and I have no idea how hard the last sorry will be.
Henrik Böving (Apr 28 2025 at 21:22):
In principle you could also use hand rolled recursion if it's the imperative part that annoys you. I guess the upcoming work on iterators might also help.
Andrew Yang (Apr 28 2025 at 21:25):
I guess I can tolerate the imperative part, but I've just tried to induction l; simp [differencesDedupLengthLEOne?]
on the sorry and the goal state exploded into 400+ lines and I don't know where to start.
Bhavik Mehta (Apr 28 2025 at 22:17):
I use MLList for this purpose, but I don't know how canonical it is
Shreyas Srinivas (Apr 29 2025 at 04:59):
Mathlib once had a lazy list definition
Andrew Yang (Apr 29 2025 at 10:07):
And it is being replaced with MLList it seems? I'll look into that too. Thanks!
But my first impression is that it is also not suited for proving things...
Kim Morrison (Apr 30 2025 at 12:37):
MLList isn't intended for proof (at all).
Shreyas Srinivas (Apr 30 2025 at 12:42):
Strictly speaking I don't see the utility of laziness in proofs
Shreyas Srinivas (Apr 30 2025 at 12:43):
Lean's thunks come with special support to make them work as thunks should( as I learnt a few months ago), but beyond that lazy lists that use thunks are just lists with extra steps to unfold them.
Andrew Yang (Apr 30 2025 at 13:38):
By “suited for proving” I mean to write an algorithm with lazy lists and verify in lean that it actually does the right thing.
Shreyas Srinivas (Apr 30 2025 at 13:39):
In that case, unless you are feeling adventurous, I suggest avoiding monadic code. It's not impossible to prove things inside the Id monad, it's just more tedious and less well documented.
Shreyas Srinivas (Apr 30 2025 at 14:21):
I started a speculative (potentially fruitless or even wildly wrong) discussion related to this on discord. Feel free to check it out and contribute
Niels Voss (Apr 30 2025 at 17:00):
I think it might actually be impossible to prove things about MLList
, at least without native_decide
. It's behavior is defined by an unsafe non positive inductive type
James Sully (May 01 2025 at 05:02):
Henrik Böving said:
upcoming work on iterators
That sounds exciting!
Last updated: May 02 2025 at 03:31 UTC