$ purs --version
0.12.5
前置き
Effect
はMonadなので例えば以下のようなコードが書けます。
main :: Effect Unit
main = do
log "hello1"
log "hello2"
log "hello3"
do記法はbind
の糖衣構文です。
main :: Effect Unit
main = log "hello1" >>= (\_ ->
log "hello2" >>= (\_ ->
log "hello3"
)
)
問い
上記処理を再現する時、Effect
はMonadである必要があるか?
- Monadでなければならない。
- Applicativeであれば十分。
- Applyであれば十分。
- Functorであれば十分。
答え
Applyであれば十分。
main :: Effect Unit
main = (\_ _ _ -> unit) <$> log "hello1" <*> log "hello2" <*> log "hello3"
ApplicativeとしてのEffect
ado記法
先ほどの例は(\_ _ _ -> unit)
と書かなければならないので使い心地が悪いです。
一般に、Applicativeであることを許すとado記法(Applicative Do Notation)が使えます。
main :: Effect Unit
main = ado
log "hello1"
log "hello2"
log "hello3"
in unit
イメージ的には以下のように脱糖衣されます。
main :: Effect Unit
main = pure (\_ _ _ -> unit) <*> log "hello1" <*> log "hello2" <*> log "hello3"
実際には一般的なApplicativeスタイルのmap
とapply
で脱糖衣されるようです。
Traversable
class (Functor t, Foldable t) <= Traversable t where
sequence :: forall a m. Applicative m => t (m a) -> m (t a)
Effect
がApplicativeであることを許せば以下のようにも書けます。
main :: Effect Unit
main = traverse_ log ["hello1", "hello2", "hello3"]
Monadの力
前の演算結果を使いたいときには結局bind
が必要になります。
randomN :: Effect (Array Int)
randomN = ado -- in以外でx, y, zの値を使うことができない
x <- randomInt 0 9
y <- randomInt 10 99
z <- randomInt 100 999
in [x, y, z, x, z, z, y]
main :: Effect Unit
main = randomN >>= \x -> logShow x
実行結果例
[3,42,319,3,319,319,42]