8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

freer-effectsでIOを扱ってみる

8
Last updated at Posted at 2017-08-06

Extensible Effects の実装ライブラリの一つである freer-effects を触ってみた時に IO の扱い方がすぐには分からなかったのでまとめました。結論としてはIOも めちゃめちゃ簡単に扱えます!

:new_moon: Effect Monad の中でIOを使う方法

example :: Eff '[IO] ()
example = do
  name <- send $ getLine
  send $ putStrLn ("Hello " ++ name)

send の型は

send :: Member eff effs => eff a -> Eff effs a

のようになっていて effs の型レベルリストの中に IO が入っていればこれを使って Eff の中で IO アクションを使うことが出来ます。

example を実行するには以下のようにします。

main :: IO ()
main = runM example

runM の型は

runM :: Monad m => Eff '[m] a -> m a

のようになっていて一つだけ効果mの残ったEffモナドをその効果を表す型に変換してくれます。今回は Eff '[IO] () -> IO () と変換する役割を担ってくれています。

:full_moon: 実行にIOを伴うハンドラを作成する方法

freer-effects の GitHub レポジトリの README.md の Example に載っている

runConsole :: Eff '[Console] w -> IO w

は Control.Monad.Freer.Internal の関数を使って実装されており、あまりお行儀がよくありません。 この Internal なパッケージを使わずに Console のハンドラを作ってみましょう。

{-# LANGUAGE TypeApplications #-}

runConsole :: (Member IO effs) => Eff (Console ': effs) w -> Eff effs w
runConsole = runNat @IO $ \eff ->
  case eff of
    PutStrLn msg -> putStrLn msg
    GetLine      -> getLine
    ExitSuccess  -> exitSuccess

すっきりと実装できました。 runNat の型は

runNat :: Member m effs => (forall a. eff a -> m a) -> Eff (eff ': effs) b -> Eff effs b

のようになっていて eff から m への自然変換を使ってEffの先頭の効果を剥がしています。
runNatの隣の@IOは TypeApplication です。 runNat の型に現れる m を IO に限定していて、これがないとコンパイル時の型推論に失敗します。

こうして定義した runConsole は次のように使います。

main :: IO ()
main = runM . runConsole $ do
  name <- getLine'
  putStrLn' ("Hello " ++ name)

runConsole で Eff '[Console, IO] () を Eff '[IO] ()に変換した後にrunMを使ってEff '[IO] () を IO ()に変換しています。

8
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?