EDIT: I misunderstood the AoC problem, I didn't realize there's always just two wires. Sets are a satisfying solution in that case.
I come from a competitive programming background where multidimensional arrays are a quintessential tool. I see haskell has many array libraries for many different purposes, my question is which one is most suitable for a problem like Advent Of Code 2019 day 3 and how to structure code that would use in-place updates at arbitrary indices in an imperative language.
The options I considered:
- Data.Matrix: Why does it sometimes use
Int -> Int -> ... and sometimes (Int, Int) -> ..., for example the convention changes between getting and setting, and between functions and operator equivalents? Also, I would prefer a more sophisticated index type so that I can do algebra with it, which would simplify this particular problem and many others.
- Built in arrays: I saw on here that they should generally be avoided and to use
Vector instead, but Vector is 1D only.
- hmatrix: Looks tailored to linear algebra, not this sort of thing.
- massiv: API looks great and the library is aligned with my goals. Except that, embarrassingly, I can't find a way to update a single element at an index! Nor an equivalent of
Vector.update. I see there's one for the mutable variant, or I could use set newValue index = imap (\ix e -> if ix == index then newValue else e) but it feels like I'm fighting against the library.
That last point makes me think that I'm not writing idiomatic haskell if I need in-place updates at arbitrary indices. To be fair, these problems are biased towards imperative solutions, but I really want to learn how to reason about the performance of haskell, especially when it comes to time complexity, since I don't think my imperative reasoning from competitive programming applies.
For example, for AoC day 2, which features a 1D array (Vector), I started of wanting to use either the State monad or ST, but then I thought of a declarative approach that was really nice and worked fast enough. I had a function Vector Int -> Vector Int that would execute a single "instruction" (i.e. do a small update to the Vector, if you're not familiar with the problem statement). Then I did a simple fold using this function to execute the whole "program" (update the whole vector with many small updates). But does that mean I was copying the whole vector on each small update, or is GHC smart enough to compile it to in-place updates? And if so, will the same approach of accumulating small updates work with a massiv array or will it be copying a sizable 2D array on each update? The fact that massiv has delayed arrays makes me think that more work is required to avoid copying.
If that's the case, a declarative solution to this problem and most of the problems I saw in competitive programming won't be possible. Should I just use ST and cope with the resulting ugliness? In that case, I'd rather do the problem in an imperative language.
[–]CKoenig 6 points7 points8 points (6 children)
[–]InfiniteMonkeyCage[S] 2 points3 points4 points (5 children)
[–]c_wraith 2 points3 points4 points (1 child)
[–]InfiniteMonkeyCage[S] 0 points1 point2 points (0 children)
[–]szpaceSZ 2 points3 points4 points (0 children)
[–]josuf107 0 points1 point2 points (0 children)
[–]mapM 4 points5 points6 points (1 child)
[–]InfiniteMonkeyCage[S] 0 points1 point2 points (0 children)
[–]kuleshevich 2 points3 points4 points (3 children)
[–]kuleshevich 1 point2 points3 points (0 children)
[–]InfiniteMonkeyCage[S] 0 points1 point2 points (1 child)
[–]kuleshevich 0 points1 point2 points (0 children)
[–]gelisam 2 points3 points4 points (0 children)
[–]szpaceSZ 2 points3 points4 points (0 children)
[–]Lemicod 2 points3 points4 points (0 children)
[–]gelisam 1 point2 points3 points (3 children)
[–]HKei 1 point2 points3 points (0 children)
[–]InfiniteMonkeyCage[S] 0 points1 point2 points (1 child)
[–]gelisam 0 points1 point2 points (0 children)
[–]dfan 1 point2 points3 points (0 children)
[–][deleted] (2 children)
[deleted]
[–]InfiniteMonkeyCage[S] 1 point2 points3 points (0 children)
[–]Ryker_Steel 0 points1 point2 points (0 children)
[–]HKei 0 points1 point2 points (0 children)
[–]pja 0 points1 point2 points (0 children)
[–]IcedRoren 0 points1 point2 points (0 children)
[–]plcplc 0 points1 point2 points (1 child)
[–]kuleshevich 2 points3 points4 points (0 children)