Dear Pipers (Pipe Smokers?),

Please accept my apologies for a lengthy example for what is undoubtedly a simple problem, but I'm struggling to know how best to simplify.

I'm writing a little command-execution package. It's primarily for my own learning, so don't worry about "couldn't I use package X...".

I have a 'systemx' function, that creates a command that will be run with stdout/stderr inherited from the process:

systemx :: (MonadError ExecError μ, MonadReader (ProcExecCtxt3 μ) ρ) => CmdSpec -> ρ (Producer [CmdSpec] μ ())

A CmdSpec is a command specification - that is, an executable name & some arguments. ProcExecCtxt3 holds an 'executor' - a function to 'execute' the command; in normal circumstances, this uses System.Process et al, but it's replaceable so that I could mock the command. Hence the free typevar μ, which is MonadIO in normal circumstances but could be a non-IO monad for mock purposes. The ExecError is thrown if the command returns non-zero. The producer is to "log" the commands run - when mocking, I can use a MonadWriter to collect the list, and use that for testing.

Now, this all works fine in simple form, where runCtxt3 is mechanics for executing via System.Process:

cmds1 :: (MonadError ExecError μ, MonadReader (ProcExecCtxt3 μ) ρ) => ρ (Producer [CmdSpec] μ ())
cmds1 = systemx (CmdSpec grep ["root", "/etc/passwd"])

cmds1' :: (MonadError ExecError μ, MonadReader (ProcExecCtxt3 μ) ρ) => ρ (Producer [CmdSpec] μ ())
cmds1' = systemx (CmdSpec grep ["foo", "/etc/motd"])

λ> :t runCtxt3
runCtxt3 :: MonadIO μ => ProcExecCtxt3 μ

λ> runExceptT $ runEffect $ for (runReader (cmds1') runCtxt3) (mapM_ warnCmd)
CMD: /bin/grep foo /etc/motd
/bin/grep: /etc/motd: No such file or directory
Left (ExecError (ExitVal 2))

λ> runExceptT $ runEffect $ for (runReader cmds1 runCtxt3) (mapM_ warnCmd)
CMD: /bin/grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
Right ()

BUT!  If I attempt to execute two commands, only the last one gets run:

cmds2 :: (MonadError ExecError μ, MonadReader (ProcExecCtxt3 μ) ρ) => ρ (Producer [CmdSpec] μ ())
cmds2 = do
  systemx grepIt
  systemx grepIt2

This is baffling me. I would suspect laziness, but that we're clearly running within MonadIO, that doesn't apply, right?

I'm sure I'm being a bit dim, but any pointers would be gratefully received.

Yours,
Martyn.

--
You received this message because you are subscribed to the Google Groups "Haskell 
Pipes" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to haskell-pipes+unsubscr...@googlegroups.com.
To post to this group, send email to haskell-pipes@googlegroups.com.

Reply via email to