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) forwhen-
fmtstring interpolation (viaPyF)