Zulip Chat Archive
Stream: new members
Topic: Idiomatic way to use Ord Typeclass to get Bools?
Agnishom Chattopadhyay (Oct 18 2023 at 15:39):
I have written the following code:
def quicksort {a : Type}
[LT a] [forall (x y : a), Decidable (x < y)]
[LE a] [forall (x y : a), Decidable (x ≤ y)]
: List a → List a
| [] => []
| x :: xs =>
(
have : List.length (xs.filter (fun y => decide (y < x))) < List.length (x :: xs) := by {
simp [List.length]
apply Nat.lt_succ_of_le
apply List.length_filter_le
}
quicksort (xs.filter (fun y => decide (y < x)))
)
++ [x] ++
(
have : List.length (xs.filter (fun y => decide (x ≤ y))) < List.length (x :: xs) := by {
simp [List.length]
apply Nat.lt_succ_of_le
apply List.length_filter_le
}
quicksort (xs.filter (fun y => decide (x ≤ y)))
)
termination_by
quicksort xs => xs.length
decreasing_by
simp_wf
simp_all
#eval quicksort [3, 4, 2, 1]
-- prints [1, 2, 3, 4]
Is there a way to write the {a : Type} [LT a] [forall (x y : a), Decidable (x < y)] [LE a] [forall (x y : a), Decidable (x ≤ y)]
declaration in a more idiomatic way? I know that there is a Ord a
typeclass, but it is not clear to me why it doesn't automatically inherit LT
or LE
Agnishom Chattopadhyay (Oct 23 2023 at 14:09):
Does anyone have any suggestions on improving this code?
Eric Wieser (Oct 23 2023 at 14:13):
You could use docs#LinearOrder, which inherits from LT and LE and Ord simultaneously.
Eric Wieser (Oct 23 2023 at 14:13):
Quick sort only makes sense on linear orders anyway, IIRC.
Alex J. Best (Oct 23 2023 at 14:16):
You could have distinct elements that compare to equal and sensibly run quicksort perhaps?
Alex J. Best (Oct 23 2023 at 14:18):
You could also use (x ≤ ·)
in place of fun y => decide (...)
it should turn out to be the same thing
Alex J. Best (Oct 23 2023 at 14:19):
Also we try to avoid non-terminal simp calls, as they are liable to break when the library you are using is changed, so we replace them with the output of simp?
Agnishom Chattopadhyay (Oct 23 2023 at 15:05):
Eric Wieser said:
You could use docs#LinearOrder, which inherits from LT and LE and Ord simultaneously.
Thanks. That seems to be the right typeclass that I am looking for
def quicksort2 {a : Type} [LinearOrder a] : List a → List a
| [] => []
| x :: xs =>
(
have : List.length (xs.filter (. < x)) < List.length (x :: xs) := by {
simp [List.length]
apply Nat.lt_succ_of_le
apply List.length_filter_le
}
quicksort2 (xs.filter (. < x))
)
++ [x] ++
(
have : List.length (xs.filter (x ≤ .)) < List.length (x :: xs) := by {
simp [List.length]
apply Nat.lt_succ_of_le
apply List.length_filter_le
}
quicksort2 (xs.filter (x ≤ .))
)
termination_by
quicksort2 xs => xs.length
decreasing_by
simp_wf
simp_all
Agnishom Chattopadhyay (Oct 23 2023 at 15:07):
Alex J. Best said:
You could have distinct elements that compare to equal and sensibly run quicksort perhaps?
Yes, true. Is there a way to refer to this kind of equality?
Another way to have this kind of a function would be to modify the signature of quicksort to
quicksort_by {a b : Type} (f : b -> a) [LinearOrder a] : List b -> List b
Agnishom Chattopadhyay (Oct 23 2023 at 15:09):
Alex J. Best said:
Also we try to avoid non-terminal simp calls, as they are liable to break when the library you are using is changed, so we replace them with the output of
simp?
Thanks, that is a great point. How do I do this?
The output of simp [List.length]
seems to be
List.length (List.filter (fun x_1 => decide (x_1 < x)) xs) < List.length xs + 1
Alex J. Best (Oct 23 2023 at 15:09):
Well I think your original version already allowed for that, by not assuming antisymmetry of LE
the LE
relation could be weaker than in a linear order and hence be something like (a,b) \le (c,d) \iff a \le c
or some such, allowing to sort on a key without comparing the elements for equality
Alex J. Best (Oct 23 2023 at 15:10):
All you really need it rw [List.length_cons]
not simp [List.length]
btw
Eric Wieser (Oct 23 2023 at 15:27):
Agnishom Chattopadhyay said:
The output of
simp [List.length]
seems to beList.length (List.filter (fun x_1 => decide (x_1 < x)) xs) < List.length xs + 1
You should be looking at the output of simp? [List.length]
, not the goal state afterwards
Last updated: Dec 20 2023 at 11:08 UTC