I have a slightly simpler version (and evidence that I am trying to
solve this myself, or at least, am stumbling around in the dark) that
stands alone (with mtl, pipes & process).
Still, somewhere, I am losing the first grep.
The second example shows that if I lose the MonadReader, all is well.
So I considered re-ordering the monad evaluation, as you will see - but
to no avail.
{-# LANGUAGE FlexibleContexts #-}
-- base --------------------------------
import Control.Monad ( Monad, (>>), (>>=), mapM_, return )
import Data.Function ( (.), ($) )
import Data.String ( String )
import System.IO ( IO, putStrLn )
-- mtl ---------------------------------
import Control.Monad.Reader ( MonadReader, ask, runReader )
-- pipes -------------------------------
import Pipes ( Producer, for, lift, runEffect, yield )
-- process -----------------------------
import System.Process ( callCommand )
-------------------------------------------------------------------------------
type CmdSpec = String
-- | "log" cmd, then "run" cmd with exec
sys :: Monad m => CmdSpec -> (CmdSpec -> m b) -> Producer [CmdSpec] m b
sys cmd exec = do
yield [cmd]
lift $ exec cmd
-- | log & run cmd, in the context of an executor
sys' :: (MonadReader (CmdSpec -> m b) n, Monad m) =>
CmdSpec -> n (Producer [CmdSpec] m b)
sys' c = ask >>= return . sys c
g1 :: CmdSpec
g1 = "/bin/grep root /etc/passwd"
g2 :: CmdSpec
g2 = "/bin/grep Ubuntu /etc/lsb-release"
-- what happens to the first grep?
main :: IO ()
main = do
runEffect $ for (runReader (sys' g1 >> sys' g2) callCommand)
(lift . mapM_ putStrLn)
putStrLn "----"
runEffect $ for (sys g1 callCommand >> sys g2 callCommand)
(lift . mapM_ putStrLn)
putStrLn "----"
runEffect $ runReader (fmap ( \ f -> for f (lift . mapM_ putStrLn))
(sys' g1 >> sys' g2))
callCommand
putStrLn "----"
runReader (runEffect <$> fmap ( \ f -> for f (lift . mapM_ putStrLn))
(sys' g1 >> sys' g2))
callCommand