Insert strategy
chikamichi opened this issue · comments
Hi,
I was looking for a FIFO implementation in Elm and just found yours. I have a question about the way insert
is implemented. As I am fairly new to Elm, it may be a rather naive question, but still: let's learn :)
Currently, insert
is:
insert : a -> Fifo a -> Fifo a
insert a (Fifo front back) =
Fifo front (a :: back)
Because a Fifo
starts as a pair of empty lists, adding a bunch of terms results in front
being empty, and back
holding the values. It explains why you needed to handle that "edge-case" in the remove
operation:
-- pattern matching
Fifo [] back ->
remove <| Fifo (List.reverse back) []
My question is this: wouldn't it be simpler to promote the first appended item to front
upon insertion, so as to avoid the above pattern matching? Something like:
insert a (Fifo front back) =
case fifo of
Fifo [] [] ->
Fifo [a] []
Fifo front back ->
Fifo front (a::back)
It would also require reworking remove
so as to have front
always be a 1-item list (or an empty list if the Fifo
is eventually emptied).
I may be completely off tracks here, it's late at night :)
Note: such a refactoring would embrace the fact that the a FIFO queue's front is actually the oldest value, that is, a single node. Your implementation leverages two lists, and some clever tricks are required to sort/move those lists; it feels like it's not necessary.
So I guess my core, underlying question was actually whether it would be possible to define the Fifo
type as being the combination of a single node (the front value) and a list (the back value). Turns out it's possible, I gave it a quick shot here: http://share-elm.com/sprout/56971b29e4b070fd20da88b5
What do you think?
I used an enumeration instead of a duo of lists, so the two core states of a FIFO are descriptive: it's either Empty
, or it's not, in which case it's the combination of a Node
(FIFO's front) and a List
. I guess one could actually get rid of the Node
and handle the FIFO with just a simple List
, but semantically it sounds good.
I think the two lists are required to make it work in all cases.
It took me a little while, but I found this case that your implementation fails:
empty
|> insert 1
|> insert 2
|> insert 3
|> remove |> snd -- Removes 1
|> remove |> fst -- should remove 2
|> assertEqual (Just 2)
It seems that only having one item in the head means that the order of the 2nd-oldest gets lost.
Ok, I reworked the implementation a little since I posted, so let me try with this case under the latest implementation.
All right, I was pretty sure about it already: I had fixed the problem in my PR #2.
See comments in #2
Closed via #2