14

ちょっとしたコードを書いていて、IO モナドでガード関数を使いたいと思っていました。ただし、IO 用の MonadPlus の定義がないため、IO ランドではガードを使用できません。MabyeT トランスフォーマーを使用して Maybe Monad でガードを使用し、すべての IO アクションを持ち上げる例を見てきましたが、必要がない場合は実際にはそうしたくありません。

私が欲しいものの例は次のとおりです。

handleFlags :: [Flag] -> IO ()
handleFlags flags = do
    when (Help `elem` flags) (putStrLn "Usage: program_name options...")
    guard (Help `elem` flags)
    ... do stuff ...
    return ()

MonadPlus またはそれ以外の宣言を通じて、IO モナドでガード関数 (または同様のもの) を取得する良い方法があるかどうか疑問に思っていました。あるいは、私のやり方が間違っているのかもしれません。上記の関数でそのヘルプ メッセージを記述するより良い方法はありますか? ありがとう。

(PS if-then-else ステートメントを使用できますが、どういうわけかポイントを無効にしているようです。多くのオプションでは、大量のネストが発生することは言うまでもありません。)

4

3 に答える 3

24

の定義を考えてみましょうMonadPlus:

class Monad m => MonadPlus m where
    mzero :: m a 
    mplus :: m a -> m a -> m a

どのように実装mzeroIOますか? type の値は、 type のIO a何かを返す IO 計算を表すaためmzero、可能なタイプの何かを返す IO 計算である必要があります。明らかに、任意の型の値を呼び出す方法はありません。またMaybe、使用できる「空の」コンストラクターが存在しないのとは異なり、絶対に を返さない IO 計算を表すことにmzeroなります。

戻らない IO 計算をどのように記述しますか? 基本的に、無限ループに入るか、実行時エラーをスローします。前者は有用性が疑わしいため、後者はあなたが立ち往生しているものです。

要するに、MonadPlusforのインスタンスを作成すると、次のようになりIOます。例外が発生しない場合は、結果を返します。例外が発生した場合は、例外を無視して代わりに evaluateの 2 番目の引数を評価します。mzeromplusmzeromplus

とは言っても、実行時例外は望ましくないと見なされることが多いため、その道をたどる前に躊躇します。そのようにしたい場合 (実行時にプログラムがクラッシュする可能性が高くなることを気にしない場合)、上記を実装するために必要なものはすべて にありますControl.Exception

実際には、guardモナド式を評価した結果に多くの ing が必要な場合、またはほとんどの条件が関数の引数として提供される純粋な値に依存している場合 (例のフラグは)@Anthonyの回答のようにパターンガードを使用してください。

于 2010-12-21T23:06:57.767 に答える
8

私は警備員でこのようなことをします。

handleFlags :: [Flag] -> IO ()
handleFlags flags
  | Help `elem` flags = putStrLn "Usage: program_name options..."
  | otherwise = return ()
于 2010-12-21T23:05:50.410 に答える
0

このために正確に作成された関数があります: Control.Monad には、関数whenとそれに対応するunless. アンソニーの答えは次のように書き直すことができます。

handleFlags :: [Flag] -> IO ()
handleFlags flags =
    when (Help `elem` flags) $ putStrLn "Usage: program_name options..."

仕様:

when :: (Applicative m) => Bool -> m () -> m ()
unless bool = when (not bool)

hackage.haskell.org のドキュメントへのリンク

さらに必要な場合は、別のパッケージへのリンクがあります。具体的にはモナド指向で、さらにいくつかのユーティリティがあります: Control.Monad.IfElse

于 2016-05-01T15:17:41.427 に答える