data Task = Task {programToRun :: String, input :: String, continue :: String -> IO (Maybe Task)} runTask :: Task -> IO (Either String Task) runTask = undefined addCont :: (String -> IO Task) -> Task -> Task addCont f t1 = Task (programToRun t1) (input t1) (\result -> do task <- (continue t1) result case task of Nothing -> Just <$> f result Just task -> do step <- runTask task case step of Left res -> Just <$> f res Right t2 -> return . Just $ (addCont f t2)) data Pipeline = Pipeline {steps :: Task} makePipeline :: String -> Pipeline makePipeline startingInput = Pipeline (Task "identityProgram" startingInput (\t -> return Nothing)) addStep :: Pipeline -> (String -> IO Task) -> Pipeline addStep pipeline step = Pipeline ((addCont step) . steps $ pipeline) run :: Pipeline -> IO () run pipeline = beginRun (steps pipeline) beginRun :: Task -> IO () beginRun task = do result <- runTask task case result of Left finalResult -> putStrLn finalResult Right nextTask -> beginRun nextTask examplePipeline :: Pipeline examplePipeline = undefined main = run examplePipeline