Add Queue datatype - #3084
Conversation
|
When adding new functionality, we tend to make somewhat larger PRs than when fixing things. In particular, a bunch of properties should be proved too. The main reason is that quite often the proofs reveal when some of functionality was written in a correct-but-hard-to-use (or reason about) manner. So basically all of #3083 will need to be done in this PR. On the other hand, asking for reviews of the intermediate steps is a good idea. |
| toList empty = [] | ||
| toList (queue dq-hd dq-tail eq) = dq-hd ∷ (dq-tail ++ (reverse eq)) | ||
|
|
||
| -- Create a Queue from a List, such that the elements |
There was a problem hiding this comment.
Probably consider fromSnocList too.
There was a problem hiding this comment.
Some alternative suggestions as to implementation.
Against @JacquesCarette , and because I'm a bit more 'OO-minded', I tend to put things like Empty/isEmpty as manifest fields of the record, because then I don't have to think about the scope management. Similarly toList, because all the pieces are at-hand without further ado... but YMMV.
As for references for this kind of implementation, probably Okasaki's "Purely functional data structures" would be the go-to citation?
Oh, and: fix-whitespace!
There is also https://doi.org/10.1017/S0956796800001489 |
So, eg.: toList-fromList : toList (fromList xs) ≡ xsThe converse direction requires some simulation relation on |
Co-authored-by: jamesmckinna <31931406+jamesmckinna@users.noreply.github.com>
Co-authored-by: jamesmckinna <31931406+jamesmckinna@users.noreply.github.com>
| to𝔹 : Q A → Bool | ||
| to𝔹 = isYes ∘ empty? |
There was a problem hiding this comment.
Similarly, should this be called null? or isEmpty? or what, in general...
|
Note: sorry for pushing a file with holes in! |
| {!!} ≡⟨⟩ | ||
| {!!} | ||
| ++-[] : ∀ {xs ys : List A} → (xs ++ ys) ≡ [] → ys ≡ [] | ||
| ++-[] {xs = []} {ys = []} xs++ys≡[] = xs++ys≡[] |
There was a problem hiding this comment.
Note that the equivalent properties in Data.Nat.Properties have more complex names:
m+n≡0⇒m≡0 : ∀ m {n} → m + n ≡ 0 → m ≡ 0
m+n≡0⇒n≡0 : ∀ m {n} → m + n ≡ 0 → n ≡ 0I personally would expect ++-[] to be a proof that xs ++ [] ≡ xs
There was a problem hiding this comment.
There are two hard things in computer science...
Descriptive names is definitely something I need to get a hold of!
|
Should instances bet put into a |
Yes to instances going into a [I'll do a full pass on all the comments / code later.] |
|
Oh no! Some properties of |
|
hmmm... circular dependencies? Does splitting the |
|
I think it would rather be splitting Or maybe moving the definitions used in the instance of |
| --- Smart Constructor | ||
|
|
||
| queue : List< A → List A → Queue A | ||
| queue [] ys = mkQ (fromList> (reverse ys)) [] (const []) |
There was a problem hiding this comment.
Ca the call to fromList> (reverse ys) be fused into something simpler?
There was a problem hiding this comment.
In my mind it should be a chips (<>>).
However, that is because I personally would expect the type of back & front to be the
other way around. This is how I visualise a queue:
,--- head of the queue from which we are dequeueing values
| ,---- split where the front ends and the back starts
v v
1 :: 2 :: 3 :: [] [<] :< 4 :< 5 :< 6
^
|
very back of the queue where we enqueue values
Values travel up the queue from right to left until they reach the head and are popped.
The operation by which we turn the back into the new front when we notice the current front
is empty is back <>> [] because _<>>_ respects the left-to-right ordering of values.
Will eventually resolve #3083. Uses the two-list method mentioned in #3072 (but in a PR not generated by an LLM this time).
There may be some poor stylistic choices due to my unfamiliarity with the standard library, for which I am sorry! There are some 'low hanging' basic operations that could still be added, but I think those would be good for separate PRs.