Haskell Turtle - getting Text output from inshellWithErr

128 Views Asked by At

What I tried:

main :: IO ()
main = do
  let eitherSuccessOrErrorLine = inshellWithErr "stack build" empty
  stackBuildOutput <- strict $ case eitherSuccessOrErrorLine of
    Shell (Left line)  -> line
    Shell (Right line) -> line
  putStr stackBuildOutput

Error message:

src/Main.hs:34:12: error:
    • Couldn't match expected type ‘Turtle.Shell.FoldShell
                                      (Either Turtle.Line.Line Turtle.Line.Line) r0
                                    -> IO r0’
                  with actual type ‘Either (Shell Turtle.Line.Line) b0’
    • In the pattern: Left line
      In the pattern: Shell (Left line)
      In a case alternative: Shell (Left line) -> line
   |
34 |     Shell (Left line)  -> line
   |            ^^^^^^^^^

src/Main.hs:35:12: error:
    • Couldn't match expected type ‘Turtle.Shell.FoldShell
                                      (Either Turtle.Line.Line Turtle.Line.Line) r1
                                    -> IO r1’
                  with actual type ‘Either a0 (Shell Turtle.Line.Line)’
    • In the pattern: Right line
      In the pattern: Shell (Right line)
      In a case alternative: Shell (Right line) -> line
   |
35 |     Shell (Right line) -> line
   |            ^^^^^^^^^^
2

There are 2 best solutions below

0
On

Solution was to create a function:

runStackBuild :: Shell ()
runStackBuild = do
  out <- inshellWithErr "stack build" empty
  liftIO $ putStrLn $ lineToText $ bifold out

and call it from main :: IO ():

putStrLn "Starting `stack build`"
sh runStackBuild
putStrLn "Finished `stack build`"
0
On

The problem is that you're attempting to pattern match on the result of runShellWithErr. runShellWithErr does return a Shell (Left Line) (Right Line), but Shell is defined thusly:

newtype Shell a = Shell { _foldShell:: forall r . FoldShell a r -> IO r }

Which is why your pattern is failing.

Instead of trying to pattern match on the result of runShellWithErr, it's cleaner to extract the line from the Either within the Shell monad. Like this:

main :: IO ()
main = do
    let successOrErrorLine = do
        buildOutput <- inshellWithErr "stack build" empty
        return $ case buildOutput of 
            Left line -> line
            Right line -> line
    result <- strict successOrErrorLine
    putStr $ show result

Which can be done more succinctly as

main :: IO ()
main = do
    let successOrErrorLine = (either id id) <$> (inshellWithErr "stack build" empty)
    result <- strict successOrErrorLine
    putStr $ show result