<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <br>
    <blockquote type="cite"
      cite="mid:20200919205727.GJ64864@straasha.imrryr.org">
      <pre class="moz-quote-pre" wrap="">    main :: IO ()
    main = Q.getContents           -- raw bytes
           & AS.parsed lineParser  -- stream of parsed `Maybe Int`s; blank lines are `Nothing`
           & void                  -- drop any unparsed nonsense at the end -- [1]
           & S.split Nothing       -- split on blank lines
           & S.maps S.concat       -- keep `Just x` values in the sub-streams (cp. catMaybes)
           & S.mapped S.sum        -- sum each substream
           & S.print               -- stream results to stdout
</pre>
    </blockquote>
    <p>There's still quite a bit that can be improved here.<br>
    </p>
    <p>First of all: comments are good. But whenever you write a
      comment, ask yourself "could I choose a better name instead?" Make
      the code self-documenting at all usage sites by choosing a good
      name once. It's a good idea for every language, but this piece of
      code is a good example of how to apply it. So, first step:</p>
    <pre class="moz-quote-pre" wrap="">       main ∷ IO ()
        main = Q.getContents
             & parseLines
             & dropUnparsed -- Add the explanation/link definition side
             & splitOnBlankLines
             & catMaybes'   -- why write "it's catMaybes", when you could just write "catMaybes"?
             & S.mapped S.sum
             & S.print
</pre>
    Do you need more functions this way to store the names? Yes. Which
    is a good thing, because they might be reusable. Of course there's a
    limit; if every function fits in half a line, you've probably gone
    too far.<br>
    <p>Second step: Thinking from left to right is a remainder from
      thinking imperatively. If you just turn around the top level of
      the code, the reader is forced to a game of ping pong while
      reading, so it can even make it harder to understand. So let's get
      rid of that (&) crowbar.<br>
    </p>
    <pre><tt>       main ∷ IO ()</tt><tt>
</tt><tt>   main = S.print</tt><tt>
</tt><tt>        . S.mapped S.sum</tt><tt>
</tt><tt>        . catMaybes'   -- by the way, there's probably</tt><tt> a better name for what it's actually doing. "dropBlankLines", maybe?
</tt><tt>        . </tt><tt>splitOnBlankLines
</tt><tt>        . dropUnparsed</tt><tt>
</tt><tt>        . parseLines</tt><tt>
</tt><tt>        $ Q.getContents
</tt>
</pre>
    <p>There's more reasons why going against Haskell's natural grain is
      a bad idea, and you provided the perfect hook to talk about it:<br>
      <br>
    </p>
    <blockquote type="cite"
      cite="mid:20200919205727.GJ64864@straasha.imrryr.org">
      <pre class="moz-quote-pre" wrap="">    (|>):   a -> (a -> b) -> b
    (|.>):  (a -> b) -> (b -> c) -> c
    (|$>)   f a -> (a -> b) -> f b
    (|*>)   f a -> f (a -> b) -> f b
</pre>
    </blockquote>
    <p><br>
      Operators have the inherent problem that there aren't many symbols
      to choose from. That means that almost all operators are
      overloaded. For example, <tt>(|>)</tt> will be confused with
      the one from Data.Sequence. Yes, there's unicode. I love unicode
      (see that sneaky little "∷" up there?) so I've tried using Unicode
      in operators before, but one single person using the project had
      their device set to a C locale and so my whole library was
      search-and-replaced. It's still 1968 out there, so there's like 10
      symbols to choose from.</p>
    <p>And even if you could use more symbols, operators still have the
      inherent problem that they can't contain any letters. What exactly
      does <tt>(>>?$>)</tt> mean? Or <tt>(|>||>)</tt>?
      Or <tt>(<<*>@)</tt>?<br>
    </p>
    <p>So why not rely on the operators that are widely used instead of
      crowbaring new ones in just so that we can keep programming in C.
      <br>
    </p>
    <p><br>
    </p>
  </body>
</html>