Last active
December 20, 2015 21:49
-
-
Save bens/6199924 to your computer and use it in GitHub Desktop.
Applicative and Monad wrappers for Command library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Control.Applicative | |
import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar) | |
import Control.Monad | |
import Control.Monad.Trans.Class | |
import Control.Monad.IO.Class | |
import System.Command | |
newtype Cmd m a = Cmd { runCmd :: m (Either (ExitCode, String) a) } | |
cmd :: MonadIO m => FilePath -> [String] -> String -> Cmd m String | |
cmd prog args stdin = Cmd $ do | |
(code, stdout, stderr) <- liftIO $ readProcessWithExitCode prog args stdin | |
if isSuccess code then return (Right stdout) | |
else return (Left (code, stderr)) | |
instance Functor m => Functor (Cmd m) where | |
fmap f (Cmd m) = Cmd (fmap (either Left (Right . f)) m) | |
instance Applicative m => Applicative (Cmd m) where | |
pure = Cmd . pure . Right | |
Cmd mf <*> Cmd mx = Cmd (go <$> mf <*> mx) | |
where | |
go (Left ef) _ = Left ef | |
go (Right _) (Left ex) = Left ex | |
go (Right f) (Right x) = Right (f x) | |
instance Monad m => Monad (Cmd m) where | |
return = Cmd . return . Right | |
Cmd mx >>= f = Cmd $ do | |
x <- mx | |
case x of | |
Left errx -> return (Left errx) | |
Right okx -> runCmd (f okx) | |
instance MonadTrans Cmd where | |
lift = Cmd . liftM Right | |
instance MonadIO m => MonadIO (Cmd m) where | |
liftIO = lift . liftIO | |
newtype CmdPar m a = CmdPar { runCmdPar :: m (Either [(ExitCode, String)] a) } | |
cmdPar :: MonadIO m => FilePath -> [String] -> String -> CmdPar m String | |
cmdPar prog args stdin = CmdPar $ do | |
(code, stdout, stderr) <- liftIO $ readProcessWithExitCode prog args stdin | |
if isSuccess code then return (Right stdout) | |
else return (Left [(code, stderr)]) | |
runPar :: Functor m => CmdPar m a -> Cmd m (Either [(ExitCode, String)] a) | |
runPar = Cmd . fmap Right . runCmdPar | |
instance Functor m => Functor (CmdPar m) where | |
fmap f (CmdPar m) = CmdPar (fmap (either Left (Right . f)) m) | |
instance (Applicative m, MonadIO m) => Applicative (CmdPar m) where | |
pure = CmdPar . pure . Right | |
CmdPar mf <*> CmdPar mx = CmdPar $ do | |
(rf, rx) <- liftIO $ do | |
vf <- newEmptyMVar | |
vx <- newEmptyMVar | |
_ <- forkIO (undefined mf >>= putMVar vf) | |
_ <- forkIO (undefined mx >>= putMVar vx) | |
(,) <$> takeMVar vf <*> takeMVar vx | |
case (rf, rx) of | |
(Right f, Right x) -> return (Right $ f x) | |
(Right _, Left ex) -> return (Left ex) | |
(Left ef, Right _) -> return (Left ef) | |
(Left ef, Left ex) -> return (Left (ef++ex)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment