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

There's still quite a bit that can be improved here.

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:

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

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.

	main ∷ IO ()
	main = S.print
	     . S.mapped S.sum
	     . catMaybes'	-- by the way, there's probably a better name for what it's actually doing. "dropBlankLines", maybe?
	     . splitOnBlankLines
	     . dropUnparsed
	     . parseLines
	     $ Q.getContents

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:

    (|>):   a -> (a -> b) -> b
    (|.>):  (a -> b) -> (b -> c) -> c
    (|$>)   f a -> (a -> b) -> f b
    (|*>)   f a -> f (a -> b) -> f b


Operators have the inherent problem that there aren't many symbols to choose from. That means that almost all operators are overloaded. For example, (|>) 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.

And even if you could use more symbols, operators still have the inherent problem that they can't contain any letters. What exactly does (>>?$>) mean? Or (|>||>)? Or (<<*>@)?

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.