-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve Data.List.Base
(fix #2359; deprecate use of with
#2123)
#2365
Merged
MatthewDaggitt
merged 4 commits into
agda:master
from
jamesmckinna:decidable-list-functions
Apr 22, 2024
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -943,13 +943,13 @@ module _ {P : Pred A p} (P? : Decidable P) where | |
filter-all : ∀ {xs} → All P xs → filter P? xs ≡ xs | ||
filter-all {[]} [] = refl | ||
filter-all {x ∷ xs} (px ∷ pxs) with P? x | ||
... | no ¬px = contradiction px ¬px | ||
... | true because _ = cong (x ∷_) (filter-all pxs) | ||
... | false because [¬px] = contradiction px (invert [¬px]) | ||
... | true because _ = cong (x ∷_) (filter-all pxs) | ||
|
||
filter-notAll : ∀ xs → Any (∁ P) xs → length (filter P? xs) < length xs | ||
filter-notAll (x ∷ xs) (here ¬px) with P? x | ||
... | false because _ = s≤s (length-filter xs) | ||
... | yes px = contradiction px ¬px | ||
... | false because _ = s≤s (length-filter xs) | ||
... | true because [px] = contradiction (invert [px]) ¬px | ||
filter-notAll (x ∷ xs) (there any) with ih ← filter-notAll xs any | does (P? x) | ||
... | false = m≤n⇒m≤1+n ih | ||
... | true = s≤s ih | ||
|
@@ -965,8 +965,8 @@ module _ {P : Pred A p} (P? : Decidable P) where | |
filter-none : ∀ {xs} → All (∁ P) xs → filter P? xs ≡ [] | ||
filter-none {[]} [] = refl | ||
filter-none {x ∷ xs} (¬px ∷ ¬pxs) with P? x | ||
... | false because _ = filter-none ¬pxs | ||
... | yes px = contradiction px ¬px | ||
... | false because _ = filter-none ¬pxs | ||
... | true because [px] = contradiction (invert [px]) ¬px | ||
|
||
filter-complete : ∀ {xs} → length (filter P? xs) ≡ length xs → | ||
filter P? xs ≡ xs | ||
|
@@ -977,13 +977,13 @@ module _ {P : Pred A p} (P? : Decidable P) where | |
|
||
filter-accept : ∀ {x xs} → P x → filter P? (x ∷ xs) ≡ x ∷ (filter P? xs) | ||
filter-accept {x} Px with P? x | ||
... | true because _ = refl | ||
... | no ¬Px = contradiction Px ¬Px | ||
... | true because _ = refl | ||
... | false because [¬Px] = contradiction Px (invert [¬Px]) | ||
|
||
filter-reject : ∀ {x xs} → ¬ P x → filter P? (x ∷ xs) ≡ filter P? xs | ||
filter-reject {x} ¬Px with P? x | ||
... | yes Px = contradiction Px ¬Px | ||
... | false because _ = refl | ||
... | true because [Px] = contradiction (invert [Px]) ¬Px | ||
... | false because _ = refl | ||
|
||
filter-idem : filter P? ∘ filter P? ≗ filter P? | ||
filter-idem [] = refl | ||
|
@@ -1021,13 +1021,13 @@ module _ {R : Rel A p} (R? : B.Decidable R) where | |
|
||
derun-reject : ∀ {x y} xs → R x y → derun R? (x ∷ y ∷ xs) ≡ derun R? (y ∷ xs) | ||
derun-reject {x} {y} xs Rxy with R? x y | ||
... | yes _ = refl | ||
... | no ¬Rxy = contradiction Rxy ¬Rxy | ||
... | true because _ = refl | ||
... | false because [¬Rxy] = contradiction Rxy (invert [¬Rxy]) | ||
|
||
derun-accept : ∀ {x y} xs → ¬ R x y → derun R? (x ∷ y ∷ xs) ≡ x ∷ derun R? (y ∷ xs) | ||
derun-accept {x} {y} xs ¬Rxy with R? x y | ||
... | yes Rxy = contradiction Rxy ¬Rxy | ||
... | no _ = refl | ||
... | true because [Rxy] = contradiction (invert [Rxy]) ¬Rxy | ||
... | false because _ = refl | ||
Comment on lines
+1029
to
+1030
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ditto. presumably? |
||
|
||
------------------------------------------------------------------------ | ||
-- partition | ||
|
@@ -1040,7 +1040,7 @@ module _ {P : Pred A p} (P? : Decidable P) where | |
... | true = cong (Product.map (x ∷_) id) ih | ||
... | false = cong (Product.map id (x ∷_)) ih | ||
|
||
length-partition : ∀ xs → (let (ys , zs) = partition P? xs) → | ||
length-partition : ∀ xs → (let ys , zs = partition P? xs) → | ||
length ys ≤ length xs × length zs ≤ length xs | ||
length-partition [] = z≤n , z≤n | ||
length-partition (x ∷ xs) with ih ← length-partition xs | does (P? x) | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this better? Naively the previous version 'looked' better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #2149 but for a TL;DR justification: I have never liked the asymmetry of having case branches which use constructors which mix different synonyms, such as
true because _
withno ¬p
... especially because in each such case here, and for the bonus of a less eager evaluation semantics (and making sure each branch is 'equally' lazy in that aspect), such things can be replaced by an appeal toinvert
.Since this PR is part of a suite aimed at removing unnecessary
with
, I might suggest, in the spirit, if not the letter of #2149 that we eventually do away with allwith
-based analysis of proofs ofDec
... but this PR exhibits a half-way house which is more 'uniform' wrt both syntax and evaluation...?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, inconsistent branches are bad - but here they were doing
yes
/no
which are consistent. The drawback to the expansion is you have to useinvert
now, and didn't have to before. (I don't believe in cross-function uniformity, that seems like overkill and even counter-productive at times.)So I'm happy with many of the other changes, it's this particular one which puzzles me. (I'm not saying you're wrong, merely that I'm not understanding your justification for the changes here.) I guess I'm not seeing the eager / lazy part.
I don't want to hold up merging this, it doesn't feel like something worth arguing about, but I would like to understand.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for saying this! But I think this is perhaps a self-inflicted wound which I should attempt to patch by reverting these changes, which don't really belong here.
I think that they ought to happen at some point (one reason I opened #2149 all those months ago... :-(), but here is not the place. So let's discuss separately, and hopefully be able to make progress downstream.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless I take your cue about cross-function uniformity (which I had also been going for... that's the second part of the changes, towards eliminating
yes
/no
altogether) and only revert the proofs aboutderun
...? But I still think I' should curb my tendency towards PR mission-creep ...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Er... now I'm not sure what to do. I've reverted the changes for
derun
, and looked again at the others, and then not reverted those (if only by reason of consistency/uniformity between branches). Not sure whether to go forward or back now!I think that I lacked the courage of my convictions to try to defend the shift from (more) strict to less in these proofs, and indeed, in proofs the issue might be moot, but there's a running theme in the history of
Decidable
about the advantages of being able to work only with the ('cheaper')Bool
eandoes
, compared with having to recompute the whole ('expensive')proof
... and AFAICT using the constructorsyes
andno
forces recomputation of theproof
field (because it asks the matcher to discern which of the constructorsReflects.ofⁿ
Reflects.ofʸ
is actually outermost around it, even though those are 'mere' proxies for the correspondingBool
...).In all the example uses in this module, the 'positive' case is lazy (the
proof
field is thrown away/not bound by_
), while the 'negative' case passes theproof
to ...contradiction
, which as observed elsewhere (eg #2243 / #2199 ), does not/cannot use its argument(s).Now I can fully believe that I have misconstrued the role of strictness here (and indeed, perhaps a truly lazy evaluator could discern
Reflects.ofⁿ
/Reflects.ofʸ
without having to do any other evaluation of the proof object underneath, but even that is doing too much traversal, eg via_×-dec_
etc.?), and perhaps any real distinctions can only be observed with very careful profiling, but having had my eyes opened by #1988 , I'm now ... sensitised to definitions being unnecessarily strict.As things stand, neither in the status quo ante nor in these revised proofs, is there yet any attempt to replace these uses of
with
by a direct, but nevertheless dependent, elimination onb because p
as a candidate proof of theDecidable
property at hand, in which not only would strictness wrt thep
argument be more clearly discernible, but also that such proofs could be directly byBool
elimination ofb
... that's properly the content of #2149 in introducing a 'true' dependent eliminator forReflects
/Decidable
proofs...... but if you're serious about replacing uses of
with
by direct dependent elimination (eg in terms of introducing explicit helper functions rather than havingwith
introduce them behind-the-scenes) then eventually such issues will need to be tackled...Sorry for such a long essay! I don't know how to distil a TL;DR for you!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say that the underlying issue was lack of understanding (of this reviewer) of the subtleties of the evaluation semantics (eager / lazy) involved, and the clear desire for things that are "pure" computations to never force the proof, since it's just going to be discarded anyways.
Part of my issue might be my shallow undertanding of all these syntax patterns and the overall effect they have.
I think the conversation has unearthed non-trivial design choices that ought to be better documented. I think your above essay has done a good job of pushing me towards 'your take' on what design is the better one.
In (unpublished, sigh) work of a long time ago, we used the words 'verdict' and 'rationale' for what is essentially 'does' and 'proof'. Maybe introducing some wrappers around
Dec
that are known to yield only verdicts (i.e. embody being lazy in the proof) would help? I'm only introducing these new words as a way to not fall into the rut of using old names with fuzzy semantics & thus muddying the actually interesting discussion.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the 'verdict'/'rationale' separation of concerns!
As to being 'better documented', I think that
Decidable
and friends (esp.Reflects
...) still represent a work-in-progress (with shout-outs to @laMudri for the work he did in pushing things forward in the direction of such separation), with #2149 and #2199 / #2243 being yet further glosses on that.Eg. the factorisation of
Decidable
towards delegation toReflects
makes one kind of sense (provided that as far as possible,Reflects
and its machinery is not/never exposed to the user!), but obscures, on the other hand, a 'direct' API of a form such as(perhaps it was like this, once upon a time? cf. endless discussion about
record
wrapping for the sake of the typechecker, and an ambient aversion to 'computed types' such asif verdict then A else ¬ A
for... green slime reasons, plus the inevitable need forwith
-based analysis downstream?)As to laziness wrt the
rationale
field, I think that the existing machinery (at least) tries to draw out the design space, not least in the definitions of_×-dec_
etc. but I think you're right that we still don't quite have the 'right' API... and won't for a while yet!