0. まとめ
liftA2
関数および liftA3
関数以外の持ち上げ関数は計算コストが高い可能性があるため、liftA2
関数および liftA3
関数や演算子 <$>
および演算子 <*>
を使用します:
liftA
-
liftM
,liftM2
,liftM3
,liftM4
,liftM5
ap
Applicative
クラスと Monad
クラスで同じ機能が提供されている場合、Monad
クラスでなく Applicative
クラスを使用します:
- 基本
return = pure
(>>) = (*>)
mzero = empty
mplus = (<|>)
- ループ
-
mapM_ = traverse_
,forM_ = for_
sequence_ = sequenceA_
-
- リストのような関数
-
mapM = traverse
、forM = for
sequence = sequenceA
msum = asum
-
可能であれば型クラス制約 MonadPlus m
でなく以下のものを使用します:
Alternarive m
Monad m
Alternarive m, Monad m
ビット演算に関して、演算子が提供されている場合は関数の中置記法でなく演算子を使用します:
(.^.) = xor
-
(.<<.) = shiftL
,(!<<.) = unsafeShiftL
-
(.>>.) = shiftR
,(!>>.) = unsafeShiftR
1. 持ち上げ関数
liftA2
関数は元はメソッドでありませんでしたが、現在は Applicative
クラスのメソッドになっています。
liftA2
関数や演算子 <*>
はメソッドのため、具体的な型ごとに最適な計算をするはずです。
演算子 <$>
は (<$>) = fmap
と定義されていて、fmap
関数は Functor
クラスのメソッドのため、最適な計算をするはずです。
liftA3
関数は liftA2
関数と演算子 <*>
を用いて定義されているため、(他にその型専用の関数がなければ) 最適な計算を期待できます。
liftA2
関数および liftA3
関数以外の持ち上げ関数は最適な計算をするとは限らないため、使用しない方が良いです。
liftA f x
liftM f x
f `liftA` x
f `liftM` x
liftM2 f x y
liftM3 f x y z
pure f `ap` x1 `ap` x2 `ap` x3 `ap` x4 `ap` x5 `ap` x6
f <$> x
liftA2 f x y
liftA3 f x y z
liftA2 f x y <*> z
liftA2 f x1 x2 <*> x3 <*> x4 <*> x5 <*> x6
liftA3 f x1 x2 x3 <*> x4 <*> x5 <*> x6
参考「[Haskell] モナド 演算子 まとめ - Qiita」
参考「[Haskell] f <$> x <*> y よりも liftA2 f x y の方が計算コストを抑えられることがある - Qiita」
参考「(<$>) - Data.Functor」
参考「(<*>) - Control.Applicative」
参考「liftA2 - Control.Applicative」
参考「liftA3 - Control.Applicative」
2. Applicative
クラスと Monad
クラス
Monad
クラスは元々 Applicative
クラスのサブクラスでありませんでしたが、現在はサブクラスになっています。
そのため、Monad
クラスと Applicative
クラスで同じ機能が提供されていることがあります。
もし初めから Monad
クラスが Applicative
クラスのサブクラスであれば Monad
クラスでは提供されなかったはずの機能のため、Applicative
クラスを使用します。
2.1. 基本
return x
x >> y
mzero
mplus x y
x `mplus` y
pure x
x *> y
empty
x <|> y
※ちなみに mempty
関数および mconcat
関数は MonadPlus
クラスのメソッドでなく Monoid
クラスのメソッドであり、ここでは関係ありません。
参考「[Haskell] モナド 演算子 まとめ - Qiita」
参考「[Haskell] モナドの計算を中断する - Qiita」
参考「pure - Control.Applicative」
参考「(*>) - Control.Applicative」
参考「empty - Control.Applicative」
参考「(<|>) - Control.Applicative」
2.2. ループ
mapM_ f xs
forM_ xs f
sequence_ xs
traverse_ f xs
for_ xs f
sequenceA_ xs
参考「[Haskell] IO () 型の for ループ - Qiita」
参考「traverse_ - Data.Foldable」
参考「for_ - Data.Foldable」
参考「sequenceA_ - Data.Foldable」
2.3. リストのような関数
mapM f xs
forM xs f
sequence xs
msum xs
traverse f xs
for xs f
sequenceA xs
asum xs
参考「traverse - Data.Traversable」
参考「for - Data.Traversable」
参考「sequenceA - Data.Traversable」
参考「asum - Data.Foldable」
2.4. MonadPlus
クラス
型クラス制約 MonadPlus m
は可能であれば Alternative m
と Monad m
に分けます。
例として、mfilter
関数の型クラス制約 MonadPlus m
を書き換えると以下のようになります。
※説明のためソースコードを一部改変。
mfilter :: MonadPlus m => (a -> Bool) -> m a -> m a
mfilter p mx = do
x <- mx
if p x
then return x
else mzero
mfilter' :: (Alternative m, Monad m) => (a -> Bool) -> m a -> m a
mfilter' p mx = do
x <- mx
if p x
then pure x
else empty
※ちなみに return x
や pure x
を mx
としてしまうと型によっては動作が変わるため、mx
には書き換えられません。
3. ビット演算
一部のビット演算に関して、ビット演算子が追加されています。
x `xor` y
x `shiftL` i
x `unsafeShiftL` i
x `shiftR` i
x `unsafeShiftR` i
x .^. y
x .<<. i
x !<<. i
x .>>. i
x !>>. i
参考「(.^.) - Data.Bits」
参考「(.<<.) - Data.Bits」
参考「(!<<.) - Data.Bits」
参考「(.>>.) - Data.Bits」
参考「(!>>.) - Data.Bits」