GHC tries to do its best with its strictness analyzer; it looks it works in many simple cases, still blowing up in non-trivial places, producing space leaks. Although I must say that space leaks may be very well produced by a redundant strictness and people who want strictness by default seem a bit luddistic to me.
My ideal language (or rather its compiler/runtime) would do complete analyses of what strategy suits each part of the program. By the way I'm a little surprised by Haskell insistence on static analysis, disregarding tracing VM and automatic run-time profiling.
That's not actually what "non-strict" means. https://wiki.haskell.org/Lazy_vs._non-strict
http://arxiv.org/abs/1504.07680
But I haven't found anything particularly satisfying from the practical point of view.And unix pipes, and node.js streams...
Your intuition about a middle ground is interesting. Perhaps one of javascript's derivative languages could come up with some syntax to make using this more intuitive, because let's face it node.js streams would be easier to use if there were some way of plumbing them together that didn't look like Java from 1999.
I was exposed to them in the Haskell music library Euterpea in the Haskell School of Music [2]. The signal processing API uses arrows.
[1] Generalizing Monads to Arrows. John Hughes. http://www.cse.chalmers.se/~rjmh/Papers/arrows.pdf
You might want to checkout purescript, which I'm pretty sure uses Monads to make stream interaction intuitive. No time for an example, but I believe there is one somewhere in the Purescript book[0].