2015-10-19 6 views
6

私はturtleを使用してHaskellでシェルスクリプトを作成しており、失敗する可能性があるコマンドを作成する際のベストプラクティスを知りたいと考えています。タートルの終了コードの作成Monad/Monad Transformerのインスタンスがないのはなぜですか?

は今、私はそうのように、ケース式の階段があります。

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... 

case式がMaybe種類に拡大した場合は、解決策はMonadインスタンスを導き出すことであろう。

ライブラリ作成者がExitCodeMonadインスタンスをまだ取得していない特別な理由はありますか、またはHaskellシェルコードのエラー処理を行う良い方法がありますか?

+3

'ExitCode'は種類が' * 'で、' Monad'型のクラスは '* - > *'型の型を必要とするため、 'ExitCode'の' Monad'インスタンスを作ることはできませんタイプ引数)。 –

+1

[多くのレベルのインデントを処理するにはどうすればよいですか?](http://stackoverflow.com/q/33005903/791604) –

答えて

5

1つの選択肢は、(.&&.) and (.||.) from Turtle.Preludeを使用しています。バッシュ

&&に類似

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

は、最初のものはExitSuccess

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

を返す場合にのみ、第2のコマンドを実行します最初のものは、彼らはこのようなあなたのコマンド(チェーンにあなたを許す ExitFailure

が関与すべてがクリーンアップを含むExitCodeを、返さなければならないことに注意して返す場合にのみバッシュ

実行中|| 2番目のコマンドに

類似):

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

それとも、あなたはそれぞれのケースで異なるクリーンアップアクションが必要な場合:

ところで

は、それがExitCodeカメbut rather by base, in the System.Exit moduleによって定義されていないことは注目に値します。

2

ExitCodeはモナドではなく、モナドトランスではありません。モナドは型引数を取る必要があり、モナド変換器は2つを取る必要があります。 ExitCodeはありません。さて、それほど問題ではないことを少し無視してみましょう。あなたは意味のある解釈を思いつくことができますか

join :: ExitCode (ExitCode a) -> ExitCode a 

ええ、私はできません。合理的には、shellは代わりにEither FailureCode()を生成するか、おそらくExceptT FailureCode IOで作業する必要がありますが、ライブラリの作者はあまりにも混乱したり、仕事に柔軟性がないと考えているかもしれません。

1

あなたはこのように階段状避けるためにMaybeTを使用することができます。

{-# 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 
関連する問題