return2について
mclh46さんの記事のreturn2についていろいろと考えました。そして「つまりreturn2は二択returnのことですね」と勝手に結論を付けました。ならば最近見ているControl.Arrowの中にもこういう選択的な機能をサポートする関数があります。
(|||) :: a b d -> a c d -> a (Either b c) d
これを使って何かできないかな?と思い、とりあえず適当に:
return2 :: Bool -> a -> Maybe a return2 x = (genSum x >>> id ||| id) where genSum t a | t == True = Left (Just a) | otherwise = Right Nothing
うん、動きますが、Maybe限定の特殊ケースなのでよろしくない。例えばListを返したい場合はJust a → [a]とNothing → のようにいちいち修正しなければならない。ここでMaybeとの共通点について考えれば、そう、答えはMonadPlusクラスです。
--Monads that also support choice and failure. class Monad m => MonadPlus m where ...
つまり、こうすればOKですね:
return2 :: (MonadPlus m) => Bool -> a -> m a return2 x = (genSum x >>> id ||| id) where genSum t a | t == True = Left (return a) | otherwise = Right mzero
テスト:
import Control.Arrow import Control.Monad stockA = 3 stockB = 0 priceA = 100 priceB = 200 --一番効率な実装はこれです、ながとさんありがとう --return2 :: (MonadPlus m) => Bool -> a -> m a --return2 True v = return v --return2 _ _ = mzero return2 :: (MonadPlus m) => Bool -> a -> m a return2 x = (genSum x >>> id ||| id) where genSum t a | t == True = Left (return a) | otherwise = Right mzero main :: IO() main = print (getA::Maybe Integer) >> print (getB::Maybe Integer) >> print (getA'::[Integer]) >> print (getB'::[Integer]) where getA = return2 (stockA > 0) priceA getB = return2 (stockB > 0) priceB getA' = return2 (stockA > 0) priceA getB' = return2 (stockB > 0) priceB
Output:
Just 100
Nothing
[100]
[]