I’m playing around with a heap implementation, which is effectively just an array under the hood. In parts of the system I swap information around depending on the sorting requirements of the data structure:
{-| Swap data between two locations in the array.
-}
swap : Int -> Int -> Array a -> Array a
swap idx1 idx2 array =
let
data1 =
unsafeGet idx1 array
data2 =
unsafeGet idx2 array
in
array |> Array.set idx1 data2 |> Array.set idx2 data1
{-| An unsafe method to get values from the array.
-}
unsafeGet : Int -> Array a -> a
unsafeGet i array =
case Array.get i array of
Just x ->
x
Nothing ->
Debug.todo "handle this"
As you can see, my types are ANY here, which is ultimately causing problems since I can’t really return a concrete value on the Nothing path.
The rest of my implementation makes sure I don’t go out of bounds when calling this, so the Debug path is ‘never’ hit. I’d like to put this in a package though, so would ultimately like to handle the exception.
For my specific case I’ll be using an Array (List number), so I could constrict the type and return an empty list on the Nothing branch: problem solved. That doesn’t allow the function to be general & in turn this isn’t a great heap implementation.
I’ve come across this pattern a lot recently, and since 0.19 stops us from being lazy and calling Debug.crash, I’d like to learn how you would handle situations like this?
Its a bit ugly, maybe someone can come up with a cleaner version…
At the end it supplies a default path which is just to return the original array if either of the Array.get operations fail - which should never happen if the rest of your implementation is correct.
Thanks guys. That certainly cleared a few questions up for me.
My sticking point was trying to keep the unsafeGet method separate, as I use it in a few other places too. But really, it’s not too much of a hassle to bring it inside a let block.
Both of your solutions will help me in different ways once I extend this to the rest of the implementation.
This gives me an idea of a function that could be added to elm-community/dict-extra and array-extra if there was one:
swap : Int -> Int -> Array a -> Array a
swap : comparable -> comparable -> Dict comparable v -> Dict comparable v
The contract would be, the functions swaps the data values located by the keys, if the keys are both valid, otherwise it just returns the data structure unchanged. There may be other dict-like data structures where swap operations are handy.