にこ、希と一緒に学ぶHaskell(番外)「extensible-effectsの基本作用」 +絵里

せーのっ

希・絵里「にこ(っち)、ハッピーバースデー!♡」

🎉 パパーン!!

にこ「わ……」



7月22日(矢澤にこ誕生日)

希「いや〜〜、うちなんかさっきまでにこっちの誕生日知らんかったわ〜〜」
にこ「な……なによもう」
希「なーんて、冗談やでw ちゃんと今日はエリチも呼んで、お祝いがてらのHaskell番外編や」

絵里「ハロー。 ノーエリー・ノーライフ!」キラッ

にこ「誕生日なのに、すごく急に駆り出されたかと思ったら、そういうことだったのね。  Haskellに関することじゃなかったらキレてたかもしれないけど、それならいいわ」


にこ「ところで絵里は、Haskellのこと知ってるのかしら?」
絵里「基本知識を備えている程度ね。 Maybe, Either, Monad。 ハラショー!」
にこ「なるほど、だいたいわかったわ」

希「今日はにこっちの誕生日やし、うち このために、にこっちが好きそうな構造を勉強したんよ」
希(エリチはちょっと置いてきぼりにしちゃうかもしれんけど……)

にこ「! なにかしら?」

希「その名も……effect-systemや!」ドドーン
にこ「!」

extensible-effects

希「といっても今回うちが使ったんは、その実装の1つであるextensible-effectsっちゅうライブラリやん。  正直なところeffect-systemが何かは……論文読んだりしたことないしわからんわ」

希(ちなみに、うち知らんかったんやけど、freerっていう、もうちょっといいらしいeffect-system実装もあるらしいで〜)

絵里「私も、なにやら『Monadスタックを置き換える』やら……って聞いたことあるわ。  Monadスタックも正直わからないけど……」
にこ「Monadスタックの詳細についてはまた今度改めて、回を開きましょうか。  私も『MonadTransliftよりも高速に動く』って聞いたことがあるわ」
希「パフォーマンスうんぬんは測定してなくて正直わからないんやけど、確かにエリチが言ってた−−Monadスタックを置き換える−−方のやつは確認したで〜」

長くなるし、基本はこっちを読んでくれな〜

希「基本的なことはこっちに書いておいたので、読んでくれな〜」

希「まあ基本はMember, SetMember, Liftでアレアレコレコレエリエリチカチカする感じやね」
にこ「へー、なるほど。  アレアレコレコレエリエリチカチカするのね。  面白いわね!」
絵里「なるほど、すごいわね!」(←わかってない)

Monadスタックの大体としての作用の合成

希「てな感じに、State Foo, Reader BarのようなモノをMemberまたはSetMemberで指定するわけやね」

context :: (Member (State Foo) r, Member (Reader Bar) r) => Eff r a
impureContext :: ( Member (State Foo) r, Member (Reader Bar) r
                 , SetMember Lift (Lift IO)
                 ) => Eff r a

希「これを見ても『Monadスタックを代替する』っていうのはよくわからへんと思う。 MonadTrans使っても同じこと書けるしな」

context' :: (MonadState Foo m, MonadReader Bar m) => m a
impureContext' :: ( MonadState Foo m, MonadReader Bar m
                  , MonadIO m
                  ) => m a

絵里「すごく見た目が同じね」
希「そう、ここまでは同じなんよ。 でも、型を具体化した時にその特徴が表れるんや!」

作用の合成やん

希「さっきのimpureContextの型を具体してみるで〜」

impureContext :: Eff (State Foo :> Reader Bar :> Lift IO :> Void) a

希「具体化する時は、右端にVoidを忘れんようにね」

にこ「(:>)って?」

希「GHCのTypeOperatorsっていう拡張で書けるようになる、いわゆる型演算子やね」
希「まあイメージ的にはこんなデータ型やね。 実際は各関数の型を制御するための幽霊型としてEmptyDataDeclを使って定義されてるんやけど」

イメージ

data a :> b = SumOfType a b

にこ「つまりは(:>)a,bという情報を持つ型……単なる型と型の足し算を表す型って感じかしら」
希「さすがやねにこっち、その通りや」

絵里「なるほど……」(←わかってない)

希「ここでは(:>)の左辺の型及び右辺の型を『作用』って言っていくで〜」

希「そして……これに対して、さっきのimpureContext'を具体化するとこんな感じのスタックになるね」

impureContext' :: StateT Foo (ReaderT Bar IO) a

希「よりわかりやすい例としては、前者は作用のみをtypeできるけど、後者は全体が各Monadのスタックを現してるから部分ぶぶんはtypeできへんね♡」

type LibraryEffect = State Foo :> Reader Bar :> Lift IO :> Void
impureContext :: Eff LibraryEffect a
type Library a = StateT Foo (ReaderT Bar IO) a
impureContext' :: Library a

にこ「なるほど、確かにスタックを積んでる感じはしないわね。 LibraryEffectの定義なんて、綺麗なものねー」

希「そうなんよ! State Foo :> Reader Barなんて、なんか『合成』って感じがせえへん!?」
にこ「するわね!!」
絵里「そうなるわね!」(←わかってない)

夏色えがおで1,2,run!

希「あとはrunReaderやらで、その合成……幽霊型を除去したりするだけやね♪」
絵里「だけね!」

-- Reader e :> rからReader eを引いてrにする
runReader :: Typeable e
          => Eff (Reader e :> r) w -> e -> Eff r w

extensible-effectsには怖いこともあってな……

希「まあeffはこんな感じやね! MonadTransと比べて楽に書けるって人もいそうやんっ」
にこ「私もさっそく試してみようかしら!」

希「でも少しだけeffには怖いものがあってな……」
にこ「」カタカタカタカタ型カタ

希「型を具体化せずに、綺麗な抽象化を保ったままミスをすると……ちょっと面白さんなコンパイルエラーが出るからそこはおおきにな♡」
にこ「グアアアアアアアアア!!」

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeOperators #-}

import Control.Eff (Eff, Member, (:>))
import Control.Eff.Exception (Exc)
import Control.Eff.Reader.Lazy (Reader)
import Control.Eff.State.Lazy (State)
import Data.Void (Void)

data Foo
data Bar

context :: (Member (State Foo) r, Member (Reader Bar) r, Member (Exc String) r) => Eff r ()
context = return ()

realContext :: Eff (State Foo :> Reader Bar :> Void) ()
realContext = do
  a <- context
  return a

main :: IO ()
main = return ()
• Couldn't match type ‘extensible-effects-1.11.0.4:Data.OpenUnion.Internal.OpenUnion2.Member'
                         (Exc String) Void’
                 with ‘'True’
    arising from a use of ‘context’
• In a stmt of a 'do' block: a <- context
  In the expression:
    do { a <- context;
         return a }
  In an equation for ‘realContext’:
      realContext
        = do { a <- context;
               return a }

...


絵里「もー、のぞみぃ、私さっきから全然わかんないわよー!」プンスコ
希「ごめんやでエリチw ほらにこっちも、そのコンパイルエラーは後で解決してあげるし、ケーキ食べよ♪」
にこ「わーい、ケーキだー! ぷりぷりのいちごが、可愛いニコニーにお似合いねー♡ なんてー♡♡♡」
希「いやそれはどうなん……」
絵里「にこは、今日も今日とて飛ばしまくりねっ♪」ニコッヨシヨシ
にこ「ぬぅわによその反応は〜〜!!」ワアァァワアァァワアァァ..

参考にした資料やで♪

筆者プロフィール

my-latest-logo

aiya000(あいや)

せつラボ 〜圏論の基本〜」 「せつラボ2~雲と天使と関手圏~」 「矢澤にこ先輩といっしょに代数!」を書いています!

強い静的型付けとテストを用いて、バグを防ぐのが好き。Haskell・TypeScript。