一番いいのは、それをどう呼ぶかではなく、そのようなコードをどのように分析するかということです。そして、そのような分析における私の最初の重要な質問は次のとおりです。
- 副作用は、関数への引数、または副作用の結果に依存しますか?
- いいえ:「効果的な機能」は、純粋な機能、効果的なアクション、およびそれらを組み合わせるメカニズムにリファクタリングできます。
- はい:「効果的な関数」は、単項の結果を生成する関数です。
Haskellで説明するのは簡単です(この文は冗談の半分にすぎません)。「no」ケースの例は、次のようなものです。
double :: Num a => a -> IO a
double x = do
putStrLn "I'm doubling some number"
return (x*2)
この例では、実行するアクション(行を印刷"I'm doubling some number"
)はx
、結果と結果との関係に影響を与えません。これは、この方法でリファクタリングできることを意味します(Applicative
クラスとその*>
演算子を使用)。これは、関数と効果が実際に直交していることを示しています。
double :: Num a => a -> IO a
double x = action *> pure (function x)
where
-- The pure function
function x = x*2
-- The side effect
action = putStrLn "I'm doubling some number"
したがって、この場合、私は個人的に、純粋な関数を因数分解できる場合だと言います。多くのHaskellプログラミングはこれについてであり、効果的なコードから純粋な部分をどのように取り除くかを学習します。
「はい」ソートの例。純粋な部分と効果的な部分は直交していません。
double :: Num a => a -> IO a
double x = do
putStrLn ("I'm doubling the number " ++ show x)
return (x*2)
これで、印刷する文字列はの値に依存しますx
。機能の一部(乗算x
2による)、我々はまだそれを考慮することができますので、しかし、すべての効果に依存しません。
logged :: (a -> b) -> (a -> IO x) -> IO b
logged function logger a = do
logger a
return (function a)
double x = logged function logger
where function = (*2)
logger x putStrLn ("I'm doubling the number " ++ show x)
他の例をつづり続けることもできますが、これで私が始めたポイントを説明するのに十分であることを望みます。あなたの利益に。
これが、HaskellがMonad
クラスを広範囲に使用する理由の1つです。モナドは(とりわけ)この種の分析とリファクタリングを実行するためのツールです。