2015-10-19 5 views
6

Ich schreibe ein Shell-Skript in Haskell mit turtle und würde gerne Best Practices für das Verfassen von Befehlen kennen, die fehlschlagen könnten.ExitCodes in Turtle erstellen. Warum gibt es keine Monad/Monad Transformer-Instanz?

Jetzt habe ich einen Fall Ausdruck Treppe, etwa so:

runRemote :: MonadIO io => Text -> Text -> io() 
runRemote oldVersion' newVersion' = sh $ do 
    mkdir "out" 
    e1 <- shell ("command " <> oldVersion') empty 
    case e1 of 
    ExitFailure n -> cleanup 
    ExitSuccess -> do 
     e2 <- shell ("command " <> newVersion') empty 
     case e2 of 
     ExitFailure n -> cleanup 
     ExitSuccess -> do 
      curDir <- pwd 
      cd (curDir <.> oldVersion') 
      e3 <- shell ("command something else") empty 
      case e3 of 
      -- ... 
      -- And so on... 

Wenn der case Ausdruck auf einem Maybe Typ wurde erweitert, würde die Lösung eine Monad Instanz abzuleiten sein.

Gibt es einen besonderen Grund, warum der Bibliotheksautor nicht bereits eine Monad Instanz für ExitCode abgeleitet hat, oder gibt es eine bessere Möglichkeit, die Fehlerbehandlung für Haskell Shell-Code durchzuführen?

+3

Es ist unmöglich, eine 'Monad' Instanz für' ExitCode' zu ​​machen, weil 'ExitCode' hat Art' * 'und der' Monad' Typklasse erfordert eine Art mit Art '* -> *' (ein Typ, der hat ein Typ Argument). –

+1

Sie mögen [Wie gehe ich mit vielen Ebenen der Einrückung um?] (Http://stackoverflow.com/q/33005903/791604). –

Antwort

5

Eine Alternative ist mit (.&&.) and (.||.) from Turtle.Prelude.

(.&&.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode

Analog zu && in heftigen Schlag

Führt den zweiten Befehl nur dann, wenn die ersten ExitSuccess

(.||.) :: Monad m => m ExitCode -> m ExitCode -> m ExitCode

kehrt

Analog zu || in Bash

Führen Sie den zweiten Befehl nur dann, wenn der erste ExitFailure

Sie ermöglichen es, an die Kette Ihre Befehle wie folgt aus (beachten Sie, dass alles wieder beteiligt sind, müssen eine ExitCode zurückkehren, einschließlich der Bereinigung):

(command1 .&&. command2) .||. cleanup 

Oder, wenn Sie jeweils unterschiedliche Bereinigungsaktionen benötigen:

(command1 .||. cleanup1) .&&. (command2 .||. cleanup2) 

Übrigens, es ist erwähnenswert, dass ExitCode nicht durch Turtlebut rather by base, in the System.Exit module definiert ist.

2

ExitCode ist keine monad, und ist kein monad transformator. Eine Monade benötigt ein Typargument und ein Monodentrafo muss zwei übernehmen. ExitCode nimmt keine. Nehmen wir nun an, wir ignorieren das nicht so kleine Problem ein wenig. Kannst du mit einer sinnvollen Interpretation von

Yeah, kann ich auch nicht kommen. Sie könnten vernünftigerweise argumentieren, dass shell stattdessen Either FailureCode() produzieren sollte, oder vielleicht in ExceptT FailureCode IO arbeiten, aber die Bibliotheksautoren haben das vielleicht für den Job zu verwirrend oder unflexibel gehalten.

1

können Sie MaybeT verwenden Staircasing auf diese Weise zu vermeiden:

{-# LANGUAGE OverloadedStrings #-} 

import Turtle 
import Control.Monad.Trans 
import Control.Monad.Trans.Maybe 

check io = do ec <- lift io 
       MaybeT $ case ec of 
         ExitSuccess -> return (Just True) 
         _   -> return Nothing 

checkShell a b = check (shell a b) 

main = do 
    dostuff 
    putStrLn "cleaning up" 

dostuff = runMaybeT $ do 
    checkShell "date" empty 
    checkShell "/usr/bin/false" empty 
    checkShell "pwd" empty 
Verwandte Themen