<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>