Deepseq versus "make invalid laziness unrepresentable"

Lightweight iterators/generators/streams/comprehensions are extremely important. I haven’t used them in Scala but I love them in Python (where I had trouble getting my non-FP colleagues to adopt them). Here’s how I would implement your example in bluefin:

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TypeOperators #-}

import Control.Monad (when)
import Bluefin.Eff (Eff, runEff, (:>))
import Bluefin.IO (effIO, runEff)
import Bluefin.Stream (Stream, forEach, yield)
import Data.Foldable (for_)
import PyF (fmt)

foo :: (e :> es) => Int -> Int -> Stream (Int, Int) e -> Eff es ()
foo n v y = do
  for_ [0..n] $ \i -> do
    for_ [0..n] $ \j -> do
      when (i + j == v) $
        yield y (i, j)

main = runEff $ \io -> forEach (foo 10 10) $ \(i, j) ->
  effIO io (putStr [fmt|({i}, {j}) |])

For another example see Break with traverse / traverse_? - #23 by tomjaguarpaw

I think it’s nice to observe that none of this is “built in” to Haskell, except do notation and [0..n]. These are all provided by libraries:

  • Streaming (via bluefin)
  • for
  • when
  • fmt string interpolation (via PyF)