Slide 1

Slide 1 text

IO (Maybe a) 2016-06-05 LTۦಈ։ൃ26

Slide 2

Slide 2 text

ͻΉΒ ͱ΋ͻ͜ ϞφϞφ

Slide 3

Slide 3 text

IO (Maybe a)

Slide 4

Slide 4 text

IO Maybe a == (IO Maybe) a 型としては無効(カインドが合わない)

Slide 5

Slide 5 text

IO (Maybe a)

Slide 6

Slide 6 text

IO String 実行するたびに文字列が返ってくる。 返ってくる文字列の内容は実行するたびに変わるかもしれない。 Maybe String 評価すると文字列もしくは空っ ぽかもしれない値が返ってくる。評価するたびに結果は変わらな い。 IO (Maybe String) 実行するたびに文字 列もしくは空っぽの値が返ってくる。値は実行するたびに変わる かもしれない。

Slide 7

Slide 7 text

ghci> :kind IO IO :: * -> * ghci> :kind Maybe Maybe :: * -> * ghci> :kind String String :: * ghci> :kind Maybe String Maybe String :: * IOやMaybeは * をうけとって *を返す。 * であるStringを渡すと * になる。 Maybe Stringは * なので IOに渡せる。 Maybe は * -> * なので IOに渡せない。

Slide 8

Slide 8 text

࣮ࡍͷ࿩

Slide 9

Slide 9 text

環境変数を取得する ghci> :type System.Environment.lookupEnv System.Environment.lookupEnv :: String -> IO (Maybe String) 変数名があれば値がとれる。 値は実行するタイミングによっては変わる 値はないこともある。

Slide 10

Slide 10 text

$ stack ghci ghci> :type System.Environment.lookupEnv "Hoge" System.Environment.lookupEnv "Hoge" :: IO (Maybe String) ghci> System.Environment.lookupEnv "Hoge" Nothing Hogeは未定義なので値はとれない

Slide 11

Slide 11 text

Hogeの値がとれる。 結果は実行するたびに違う可能性がある。 $ Hoge="abc" stack ghci ghci> System.Environment.lookupEnv "Hoge" Just "abc" $ Hoge="" stack ghci ghci> System.Environment.lookupEnv "Hoge" Just ""

Slide 12

Slide 12 text

値をつかってみる

Slide 13

Slide 13 text

愚直にdoを使ってみる import System.Environment import Data.Maybe sample = do -- IOͷͨΊͷdo maybeHoge <- lookup "Hoge" -- maybeHoge ͸ IO͕ͱΕͯ Maybe Stringɹͱ͍͏ܕ ʹͳ͍ͬͯΔ return $ do -- Maybe ͷͨΊͷdo IOͷdoͷதʹ͔͚ΔΑ͏ʹ return Λ͚ͭΔ ɹɹ hoge <- maybeHoge -- hoge͸Maybe͕͸ͣΕͯ String ɹɹ return . putStrLn $ hoge -- hogeͷ಺༰Λग़ྗɻίϯύΠϧ͕௨ΔΑ͏ʹ returnΛ ͚ͭͯ͋͛Δ sampleの型は IO (Maybe (IO ())) Hogeが定義されていたら、標準出力に内容を出力。未定義 だったときのことが考慮されていないため、3重になって いる doが二重になってあたりもつらい。

Slide 14

Slide 14 text

さっき作ったsampleを使う $ stack ghci ghci> sample >>= fromMaybe (putStrLn "not found Hoge") not found Hoge 未定義の時の処理を追加して使う。 Hogeが未定義なのでfromMaybeで追加し た処理が動いている $ Hoge=aaa stack ghci ghci> sample >>= fromMaybe (putStrLn "not found Hoge") aaa こっちはHogeがあるのでHogeの内容 が表示されている

Slide 15

Slide 15 text

実行するのが大変。。。 値がなかった時の処理を組み込んでおく

Slide 16

Slide 16 text

値がない場合はnot foundに 型は IO () sample2 = do maybeHoge <- lookupEnv "Hoge" let hoge = fromMaybe "not found" maybeHoge -- ͜ͷ࣌఺ͰMaybeΛ֎͓ͯ͘͠ɻ NothingͳΒ "not found"ʹͳΔ putStrLn hoge $ stack ghci ghci> sample2 not found $ Hoge="aaa" stack ghci ghci> sample2 aaa 使うのも簡単

Slide 17

Slide 17 text

しかし 処理が追加できる柔軟性を
 失ってしまった

Slide 18

Slide 18 text

IO と Maybeの組み合わせではなく IOとMaybeをまとめて扱えたらいいのに

Slide 19

Slide 19 text

*0 .BZCF 4USJOH IO (Maybe String) X String 9 4USJOH

Slide 20

Slide 20 text

それ MaybeT でできるよ

Slide 21

Slide 21 text

* -> * を受け取れる ghci> :kind MaybeT MaybeT :: (* -> *) -> * -> * ghci> :kind MaybeT IO MaybeT IO :: * -> * ghci> :kind IO IO :: * -> * ghci> :kind Maybe Maybe :: * -> *

Slide 22

Slide 22 text

*0 .BZCF 4USJOH IO (Maybe String) MaybeT IO String .BZCF5*0 4USJOH

Slide 23

Slide 23 text

MaybeT IO Stringはメンバに IO (Maybe String)を持っているだけの構造 簡単に行ったり来たりできる .BZCF5*0 4USJOH *0 .BZCF 4USJOH runMaybeT MaybeT

Slide 24

Slide 24 text

sample3の型は MaybeT IO String import System.Environment import Data.Maybe import Control.Monad.Trans.Maybe sample3 = do hoge <- MaybeT $ lookupEnv "Hoge" -- IO (Maybe String)Λ MaybeT IO Stringʹม׵ͨ͠ɻശ͸ҰͭͳͷͰ <- Ͱ஋Λͻͬͺͯ͘Δͱ Stringʹͳ͍ͬͯΔ lift $ putStrLn hoge -- IO () ͳͷͰ MaybeT IO () ʹม׵

Slide 25

Slide 25 text

sample3を使ってみる $ stack ghci ghci> runMaybeT sample3 -- IO (Maybe String)ʹͳΔͷͰ࣮ߦͰ͖ͯɺ Maybe Stringʹ ͳΔ Nothing ghci> runMaybeT sample3 >>= maybe (putStrLn "not found") (const return ()) -- ޙ͔Βॲཧͷ௥Ճ΋Ͱ͖Δ "notFound" $ Hoge=aaa stack ghci ghci> runMaybeT sample3 aaa ghci> runMaybeT sample3 >>= maybe (putStrLn "not found") (const return ()) aaa ghciはIO aな型は実行してaにしてくれる機能があるっぽい。
 MaybeTをつかうと1重のモナドとして扱えて便利。 元に戻すこともできる

Slide 26

Slide 26 text

sample3と同じ動きをするように書いてみる sample1_5 = do maybeHoge <- lookupEnv "Hoge" case maybeHoge of Just hoge -> putStrLn hoge >> return (Just ()) Nothing -> return Nothing 一度Maybeを自分で解いて、再度同じようになるように値を構 築している。最初の例はMaybeを解かずにdoをつかったため、 IO (Maybe (IO ())) となってしまった。

Slide 27

Slide 27 text

4USJOH .BZCF 4USJOH .BZCF 4USJOH *0 .BZCF5*0 4USJOH *0 4USJOH return return return return runMaybeT MaybeT lift

Slide 28

Slide 28 text

まとめ

Slide 29

Slide 29 text

まとめ • MaybeTをつかうと • 2重のモナドが1重のように扱える • 2重のモナドといったりきたりできる • MaybeTにする方法が用意されてるので • MaybeTに統一すれば操作が簡単