I notice that List.scanl has been dropped from elm 0.19. I’m not challenging this decision, but rather I am trying to get a better understanding of the rationale behind the development of elm (e.g. I see a gradual distancing of elm from its Haskell origins).
I realise I can create my own scanl function such as:
scanl : (a -> b -> b) -> b -> List a -> List b
scanl fn b =
scan a bs =
case bs of
hd :: tl ->
fn a hd :: bs
List.foldl scan [b] >> List.reverse
Personally I find scanl quite useful and I was wondering what the rationale was for dropping it. Is the idea to encourage higher level functions like this be written by users and leave elm with a minimal set of set of more primitive functions? Or something else perhaps?
Until Evan tells us, we can only guess. My guess would be that it’s a “niche” function, better fit for elm-community/list-extra. (If that’s true, the question is… do the maintainers know? and do they want to fill the gap?)
Yeah I was just upgrading list-extra for the alpha, and I was getting a compiler error that List.scanl didnt exist. Since we had other scan functions like scanl1, I thought it would be awkward if scanl was missing, so I just copied and pasted the old scanl implementation into List.Extra.
Regarding keepIf, for just the first alpha version of 0.19, take was renamed keep. Thats why I changed takeIf to keepIf and then reverted it again when the alpha progressed.
It seems to me that the selection of functions that make it into the standard library is an opportunity not simply to provide particular functionality, but to send a message that the approach they embody is explicitly encouraged. i.e. it can signal an ‘elm way of doing things’.
This is partly why I was slightly surprised to see scanl dropped, as to my (relatively new) understanding of functional programming, it offers a concise and elegant approach to sequential list processing. Its conceptual link with folding makes it easy to understand and to me at least, doesn’t feel particularly ‘niche’ or ‘rare’.
I raised this issue because I wondered if I am missing something, an ‘elm approach’ which makes scanning redundant or misaligned with a more favoured approach. As an analogy, I can see why Haskell’s list comprehension is not available in elm, instead encouraging map and filter to provide a clearer and arguably more robust approach.
I don’t think (nor expect) that my response will change anything here, but I’d like to tell everyone that I’ve used and use scanl regularly in my code (in both Elm, Elixir and Haskell), and frequently point out its existence to other people, since it happens often that people either ‘roll their own’ since its use case is rather common.
scanl is one of the functions that makes working in a functional way with lists simple, rather than complex. I’ve seen multiple people new to functional programming be stuck on their code since they did not know how to do something which is commonly done using a loop in an imperative (and possibly object-oriented) language.
I think that having these kinds of ‘Look, working with lists does not have to be a hassle’-functions in a place that is highly visible for newcomers is valuable for understanding Elm and functional programming in general.
To expand on the examples above I find scanluseful when you are performing sequential actions on a list but then need to extract some value from the processed list that might be anywhere within it. In my field, geometric problems can often fall into this category.
@Janiczek, I know you are a fan of Advent of Code, so a good example is Day 11, 2017, where it was necessary to find furthest distance away from a start point along the trajectory of a random walk. See my solution in Elm that uses scanl for part 2 (and compare with foldl in part 1):
I should add, scanning is often more easily applied in lazy list evaluation where you need to cumulatively process a list until some condition is met. This may explain why it is more common in lazy languages like Haskell than eager ones like Elm, but nevertheless, as @Qqwy says, I find it a helpful signpost towards concise functional solutions to list processing.
I understand what it does compared to foldl yet I still didn’t use it in my actual application/library code. I’m not sure puzzles count much.
On the other hand, I can see myself using it in Haskell with the infinite lists + dropWhile / takeWhile combo. These things (I’m sure there are others that it’s great for) aren’t of much use in Elm without explicitly using Stream or LazyList or something else of the infinite nature.
It still seems to me like scanl on the List type is niche and thus OK to have in List.Extra. I’d still like to see examples of usage in Elm, to compare with my “how would I implement this” instincts.
For me as an academic doing data science and visualization, “puzzles” form a large part of my coding (real problems, not just Advent of Code style fun puzzles). As I mentioned above, spatial trajectory analysis can make good use of scanning.
But that aside, here is one simple example of using scanl to generate data for CUSUM charts which I use quite often in data analysis: