4
1

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 3 years have passed since last update.

Freer Effectsが、だいたいわかった: 14 Freer Effectsで、IOモナドなどの既存のモナドを使用する

Last updated at Posted at 2019-09-26

Freer Effectsが、だいたいわかった: 14 Freer Effectsで、IOモナドなどの既存のモナドを使用する

はじめに

Freer Effectsでは、型リストの要素であるモナドの効果を、ひとつずつ処理していく。しかし、IOやSTなどのモナドは、そのようなやりかたでは処理できない。IOなどのモナドは「そのまま」処理系にわたす必要がある。

また、Freer Effectsのわくぐみ以外の、たとえばモナド変換子といったわくぐみを使ったモナドについても、Freer Effectsの仕組みでは処理できない。

そのようなFreer Effectsの範囲外にあるモナドを利用するには、これらのモナドを型リストの最後の要素として残しておき、「そのまま」とりだすような仕組みが必要になる。

目次

(0). 導入

  1. Freeモナドの概要
    • Freeモナドとは
    • FreeモナドでReaderモナド、Writerモナドを構成する
  2. 存在型(ExistentialQuantification拡張)の解説
  3. 型シノニム族(TypeFamilies拡張)の解説
  4. データ族(TypeFamilies拡張)の解説
  5. 一般化代数データ型(GADTs拡張)の解説
  6. ランクN多相(RankNTypes拡張)の解説
  7. FreeモナドとCoyoneda
    • Coyonedaを使ってみる
    • FreeモナドとCoyonedaを組み合わせる
      • いろいろなモナドを構成する
  8. Freerモナド(Operationalモナド)でいろいろなモナドを構成する
    • FreeモナドとCoyonedaをまとめて、Freerモナドとする
    • Readerモナド
    • Writerモナド
    • 状態モナド
    • エラーモナド
  9. モナドを混ぜ合わせる(閉じた型で)
    • Freerモナドで、状態モナドとエラーモナドを混ぜ合わせる
      • 両方のモナドを一度に処理する
      • それぞれのモナドを、それぞれに処理する
  10. 存在型による拡張可能なデータ構造(Open Union)
  11. 追加の言語拡張
    1. ScopedTypeVariables拡張
    2. TypeOperators拡張
    3. KindSignatures拡張
    4. DataKinds拡張
    5. MultiParamTypeClasses拡張
    6. [FlexibleInstances拡張] (
      https://qiita.com/YoshikuniJujo/items/eb70e7978f333ef3b514 )
    7. OVERLAPSプラグマ
    8. FlexibleContexts拡張
    9. LambdaCase拡張
  12. Open Unionを型によって安全にする
  13. モナドを混ぜ合わせる(開いた型で)
    • FreeモナドとOpen Unionを組み合わせる
    • 状態モナドにエラーモナドを追加する
  14. Freer Effectsで、IOモナドなどの既存のモナドを使用する
  15. 左結合による効率の低下
  16. 型合わせした並び (Type aligned sequence)
  17. 「型合わせした並び」で「左結合による効率の低下」をふせぐ
  18. いろいろなEffect
    • 関数send, handleRelayなどを作成する
    • NonDetについてなど
    • Trace
    • Fresh, Cut
    • Coroutine

開かれた直和型から最後の効果を取り出す

src/OpenUnion.hs
extract :: Union '[t] a -> t a
extract (Union _ tx) = unsafeCoerce tx

公開されたAPIを使って、まともに構成されたUnion型の値であれば、定義中の(Union _ tx)で_(ワイルドカード)がマッチする値は0であるはずだ。なので、unsafeCoerceはその値を確認しなくても安全に適用できる。モジュールOpenUnionのエクスポートリストに関数extractを追加しておく。

モジュールEffのOpenUnionを導入するimport文のインポートリストに関数extractを追加したうえで、関数runMを定義する。

src/Eff.hs
runM :: Monad m => Eff '[m] a -> m a
runM (Pure x) = return x
runM (u `Bind` q) = runM . q =<< extract u

関数extractを適用して「最後に残った効果」を取り出している。取り出されたモナドがかえす値をバインド演算子で、qにあたえ、その結果にさらに関数runMを適用することで、Eff '[m] aをm aに変換している。

StateモナドとIOモナドとを混ぜ合わせる例

モジュールSampleに「StateモナドとIOモナドとを混ぜ合わせる例」を追加する。

src/Samples.hs
runMSample :: (Member (State Integer) effs, Member IO effs) => Eff effs ()
runMSample = do
        (a :: INteger) <- get
        inj (print a) `Bind` Pure

この形は何度も出てきているが、Bind (inj m) Pureとすることで、モナドmをEff effs aのかたちに変換することができる。ここではmがprint aだということ。試してみよう。

*Samples> runM $ runMSample `runState` 123
123
((),123)

print aによって取り出した状態が表示されている。

まとめ

最後に残った効果がモナドであったときに、それをそのまま取り出す関数runMを定義した。これを使えば、Freer Effectsのわくぐみの外で定義されたモナドをFreer Effectsで定義された効果と混ぜて使うことができる。ただし、そのような生(なま)のモナドは型リストの末尾に置かれ、「最後に取り出す」ことしかできず、また複数指定することもできない。

4
1
0

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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?