
It never makes sense to use foldl on lists in Haskell (2019) - tirumaraiselvan
https://github.com/hasura/graphql-engine/pull/2933#discussion_r328821960
======
chc
It's worth noting, if you either just read the title or are skimming the post,
that "never" is used here specifically in the context of a language like
Haskell. If your language uses strict evaluation (like most languages), it
probably makes sense to use a left fold on lists.

~~~
TylerE
Most other languages don't use singly linked lists to begin with.

Because they suck.

~~~
cryptonector
In Haskell, because of laziness, lists work well enough, but they're really
just a thunk container. Conduits are better.

~~~
Retric
The way modern memory works linked lists are practically a denial of service
attack on system performance. IMO, like goto’s it’s better to just forget they
exist.

~~~
jerf
Linked lists stink as a manifested in-memory data structure. However, if what
your linked list is is "{concrete value} : {code to generate the rest of the
list}" and you walk it once, never having the whole thing at once, it isn't
necessarily bad. That is the point cryptonector is making. The memory
inefficiency of a linked list doesn't matter if you never really have it "in
memory".

That said, the ready availability of linked lists in Haskell does mean that
you end up with rather more strictly-manifested linked lists than you might
like, since any of them can be manifested as actual linked lists. If you're
using Haskell though, while you haven't exactly completely given up on that
sort of performance, it must not be foremost on your mind.

~~~
Retric
That’s frankly not a linked list.

~~~
jerf
Haskell has a duality between flow control and data structures as a result of
its laziness. It is a perfectly valid point of view to look at such a thing as
a control structure, rather than a data structure.

 _Technically_ , if you want to _really_ understand how the "IO monad" does
its thing, this is actually how it works. Technically your program declares a
probably-infinite data structure that contains all possible paths your code
could take, e.g., if you have a "if user input is negative then do X else do
Y", what you really have is a data structure representing the if-then clause.
What keeps the infinite data structure from being manifested in RAM is that
the whole thing is resolved lazily, so only one branch will be actually
evaluated. That's why the "IO monad" is actually pure; it simply "purely"
creates a huge data structure that is resolved by an interpreter later. In the
theoriest of theories, an IO value in Haskell really doesn't execute anything
either and the whole language is pure... it is only the interpretation of the
IO value that finally interfaces with the real world.

It isn't always the most helpful perspective and you can become an expert
Haskell programmer without ever looking at your program this way, but
_technically_ , under the theory hood, that's what's happening.

------
Chinjut
It perhaps rarely makes sense, but not 100% never. You might at some point in
your life have a situation where you want to fold an operator with short-
circuiting behavior left-associatedly over a list (thus, with later elements
of the list controlling whether short-circuiting happens skipping evaluation
of-and-concerning earlier elements of the list). In this case, foldl is the
way to go. foldl' can't execute the desired short-circuiting, and foldr can
but only in the other direction, of right-associated bundling with earlier
elements of the list controlling the short-circuiting of-and-concerning later
elements of the list.

If there's ever a situation where you want to reverse a list and then foldr
over it, taking advantage of the short-circuiting foldr allows, well, that
reverse and then foldr is essentially the definition of foldl, have at it.

~~~
erikpukinskis
_And you may find yourself_

 _Living in a shotgun shack_

 _And you may find yourself_

 _In another part of the world_

 _And you may find yourself_

 _folding an operator with short-circuiting behavior left-associatedly over a
list_

Let the data go by....

~~~
bryanrasmussen
Aren't you supposed to ask yourself something before letting anything go by?!?

~~~
bonzini
"How did I get here" seems appropriate.

------
ISO-morphism
I'd like to take the opportunity to thank lexi-lambda for multiple thoughtful
contributions to the programming community. In the world of open source and
software in general there are names that are recognizable - some feel more
like "brands," intentionally cultivated, but I don't feel like I'm really
being sold something when I see a post/article/wall of text from lexi-lambda,
rather through repeated examples I've come to feel a bit of excitement that
someone who has gone much deeper down an interesting technical path than I has
taken the time to meaningfully share their knowledge and experience for the
benefit of others. Thank you.

------
candeira
The linked comment is great. However, I think the HN heading is confusing,
particularly for people who may not know about the existence of Haskell and
its lazy-by-default semantics.

The linked comment recommends using strict/eager fold-left instead (`foldl'`
in Haskell) of using lazy fold-left (`foldl`, with no trailing apostrophe).
It's not saying that you shouldn't use fold-left in any language.

Reading the HN title alone, in its front-page context, it looks like it's
saying that it's the fold-left generic operation that's wrong for lists, and
not just `foldl`, Haskell's default lazy implementation of fold-left.
Paradoxically, following the guidelines and re-using a boiled-down version of
the linked comment's first line results in the line being misleading and/or
link-bait (I guessed what it was about, but I still had to go and check).

For some time I've thought that the HN policy of disallowing editing of post
titles, while correct, can be taken too far, and that many titles would be
better with some annotation.

In this case, "It never makes sense to use [lazy] foldl on lists [in Haskell,
use foldl' instead]" would be a better title. A bit awkward and maybe
inelegant, but it says what the article means. Out of its original context,
the HN title doesn't say what the posted article means.

Maybe "Lazy foldl versus strict foldl' in Haskell" would have been an even
better title, if the guidelines allow for using one's discretion on when to
disregard them.

Other common case is that of headlines in the first person: "My X ..." would
often be improved by editing it to "[Name's] X ..." or "[Name of whatever X
is] ..." while leaving it otherwise unchanged.

\--

I don't know if @sama will get summoned to this comment like he would if this
were Twitter, but it doesn't hurt to try.

~~~
Talanes
The OP mentioned in another reply that their submitted title did include a (in
Haskell) at the end, and it was dropped (automatically?)

~~~
masklinn
> and it was dropped (automatically?)

I don't think HN automatically drops title items. Mods edit them. Mods
regularly edit them to be significantly worse, because they'd rather the title
exactly match the "article's" than the title being useful in and of itself.

------
hawkice
What does this random minor github discussion have to do with the submitted
title? I'm on mobile, does 'foldl' appear on the page on desktop?

~~~
Arnavion
It is a direct link to a comment on the code of the PR.

Here it is for your convenience: [https://paste.rs/SWO](https://paste.rs/SWO)

~~~
cortesoft
Yeah, that doesn't show up anywhere on the page on mobile. Thanks!

~~~
sealjam
This was the same for me. I think it’s because it was a line-level GitHub
comment and the line has now changed. It is possible to expand the post if you
click “Show Outdated” on the two collapsed posts underneath the comment
saying:

“LGTM aside from two minor comments”

------
jolmg
> Now, in this case, this is a silly operation, since foldr (:) [] is just a
> complicated identity function on lists, but we could imagine a slightly more
> complicated function, such as one that doubles each element in a list.

This whole post is great, but this part would be less awkward and easier to
understand with a simpler example of more practical use like:

    
    
      and = foldr (&&) True
    

or

    
    
      all f = foldr (&&) True . map f
    

x && y doesn't evaluate y if x is False.

~~~
danharaj
Maybe, but foldr (:) [] ~ id is an illuminating fact in its own right that is
worth pausing to understand.

~~~
patrickthebold
To spell things out a bit more: A list is fundamentally constructed from []
and :. In the sense that a list is either empty [] or a head : tail, where
tail is another list.

One might write 1:2:3:4:[].

foldr is deciding where to map [] and :. So for example:

    
    
      [] => 0
      : => +
    

Turns the above list into 1+2+3+4+0.

With that understanding, foldr (:) [] becomes:

    
    
      [] => []
      : => :
    

which is fairly clearly the identity.

~~~
toolslive
> foldr is deciding where to map [] and :

This is a way better explanation than the cryptic:

    
    
        " it (foldr) takes the second argument and the last item of
        the list and applies the function, then it takes the 
        penultimate item from the end and the result, and so on.
        See scanr for intermediate results. "

------
MichaelMoser123
Haskell seems to be used with projects that are heavy on parsing (shellcheck,
pandoc, graphql). I think that's partly because there just isn't a parser
generator that feels right for general purpose languages, with haskell you
seem to have less of a mismatch between the parser itself and handling of the
parse tree. Is that a correct impression?

------
thayne
What is the connection between the title and the linked PR. Where is the
explanation of why it never makes sense?

~~~
thayne
ah, apparantly it is hidden on the page when you follow the link on mobile,
but is visible on the desktop version :shrug:

------
im3w1l
So if I got that right, the future best practice will be to use
foldMap/foldMap' on all data structures unless you require a particular
associativity.

~~~
MaxGabriel
That doesn’t sound like the correct reading to me, because foldMap and
foldl/foldr have different type signatures

[https://www.stackage.org/haddock/lts-15.4/base-4.13.0.0/Prel...](https://www.stackage.org/haddock/lts-15.4/base-4.13.0.0/Prelude.html#v:foldMap)

~~~
im3w1l
Yeah, but they solve basically the same problem.

As I mentioned, foldMap requires associativity. Per your link I guess it also
requires existence of a neutral element (whereas foldr instead makes you
specify a starting element).

------
microtherion
For a second there, I thought "foldl" was the opposite of "hodl" in terms of
cryptocurrency speculation.

~~~
didgeoridoo
Maybe while the world is on fire we could have a moratorium on downvotes for
attempts at levity?

------
ionforce
Poorly written headline.

------
dependenttypes
The issue is basically that haskell is a lazy language which ends up leaking
memory left and right. Most people that I have talked to about it seem to
agree that haskell would be a trillion times better if it was a strict
language. At least we now have Idris.

~~~
wyager
If Haskell was a strict language, we would never have invented monadic effects
and would still be using () -> to (poorly) represent effects. Laziness forces
you to avoid many such janky hacks that pervade almost every single strict
language in existence (including most strict "functional" languages, where
"functions" are, half the time, actually not), and which most people aren't
even aware are janky hacks until they program with some kind of typed effect
system

~~~
dependenttypes
> we would never have invented monadic effects and would still be using () ->
> to (poorly) represent effects

What makes you think that?

> where "functions" are, half the time, actually not

Please elaborate.

~~~
yakshaving_jgt

      function foo() {
        print('effects');
      }
    

The above is not a function. It's a procedure.

~~~
dependenttypes
And what about

    
    
        bar = error "effects"

~~~
08-15
It's a partial function that always returns _|_. Haskell is not a total
language (and whether a total language can be practical is yet to be seen).

~~~
dependenttypes
Sure, but what it returns is not an issue. The issue is that it does have an
effect.

~~~
08-15
Whether it has an effect is not an issue. The issue is that it is
referentially transparent.

Sure, we could have a discussion about whether partiality is an effect.
Someone, somewhere is having that discussion. If the Haskell committee had had
this discussion in 1987, chances are we wouldn't have Haskell at all.

------
abhayb
I'm going to take inspiration from @lexi-lambda and respond in mini-
composition form. Note that great writers write essays. I, write compositions.

It's just like Haskell for the crucial difference between two functions to be
denoted by prime. For half of the essay I thought that this was a deep
philosophical treatise about the degenerate case equality of lazy and strict
languages. But, in reality, fold and fold-prime (can you inline code in HN?)
are totally different functions.

And like with all pairs of things in Haskell once you learn the fundamental
difference between them, the fact of that difference becomes obvious. So
obvious that you don't know how anyone could possibly confuse the two. And so
you call the method everyone should use foldl-prime even though a casual
programmer doesn't even know that "single-quotes" are an acceptable value
name. When you could have just called it foldl and moved the old one to the
deprecated module.

~~~
thenewnewguy
This seems like a weird complaint - basically everywhere in programming two
variables/functions/classes/etc with different names are different things. I'd
be much more surprised if appending a ' to a function name did nothing in
haskell.

> When you could have just called it foldl and moved the old one to the
> deprecated module.

1\. Most people aren't a fan of randomly changing existing library functions

2\. The lazy (non-prime) version of foldl isn't useless! There's even a
section at the end of the post explaining how this post _only applies to
lists_ and that with other data structures foldl and foldr' are actually
useful.

