mp in haskell

28
MP in Haskell

Upload: kent-ohashi

Post on 10-Apr-2017

276 views

Category:

Software


0 download

TRANSCRIPT

Page 1: MP in Haskell

MP in Haskell

Page 2: MP in Haskell

MP = Monadic Programming

1. モナドとは何か2. モナドの基本的な扱い方3. モナド変換子の使い方

Page 3: MP in Haskell

自己紹介

Page 4: MP in Haskell

(defprofile 大橋 賢人 [OHASHI Kent] :company 株式会社オプト テクノロジー開発2部 :github @lagenorhynque :twitter @lagenorhynque :languages [Python Haskell Clojure Scala English français Deutsch русский] :interests [プログラミング 語学 数学])

Page 5: MP in Haskell

モナド(Monad)とは

一言で言えば、 >>= (bind) できる型クラス(type class)。

m a -> (a -> m b) -> m b

型クラスFunctor, Applicativeの上位互換。

-- Haskell class Applicative m => Monad m where (>>=) :: forall a b. m a -> (a -> m b) -> m b return :: a -> m a ...

// scalaz.Monad trait Monad[F[_]] extends Applicative[F] with Bind[F] { abstract def bind[A, B](fa: F[A])(f: (A) ⇒ F[B]): F[B] abstract def point[A](a: ⇒ A): F[A] ... }

Page 6: MP in Haskell

モナドの具体例

例えば、 。Maybe

型クラスFunctor, Applicative, Monadのインスタンスになっている。

Page 7: MP in Haskell

Functorの fmap / <$>

(a -> b) -> f a -> f b

n :: Maybe Int n = Just 1 f :: Int -> String f = \x -> show x

-- fmap fmap f n -- <$> f <$> n -- >>= による実装 n >>= return . f -- do記法による実装do a <- n return $ f a

Page 8: MP in Haskell

Applicativeの <*>

f (a -> b) -> f a -> f b

n :: Maybe Int n = Just 1 f :: Maybe (Int -> String) f = Just $ \x -> show x

-- <*> f <*> n -- >>= による実装 n >>= \a -> f >>= \g -> return $ g a -- do記法による実装do a <- n g <- f return $ g a

Page 9: MP in Haskell

Monadの >>=

m a -> (a -> m b) -> m b

n :: Maybe Int n = Just 1 f :: Int -> Maybe String f = \x -> Just $ show x

-- >>= n >>= f -- do記法による実装do a <- n f a

Page 10: MP in Haskell

同種のモナドを扱う場合

例えば、 Maybe を単独で使う場合

Page 11: MP in Haskell

同種のモナドを扱う場合

(1) パターンマッチ

構造に注目して分解(unapply, destructure)する。

data User = User { firstName :: Maybe String, lastName :: Maybe String } deriving Show

userName :: User -> Maybe String userName User {firstName = Just f, lastname = Just l} = Just $ f ++ " " ++ l userName _ = Nothing

Page 12: MP in Haskell

同種のモナドを扱う場合

(2) 高階関数

高階関数 >>=, etc.を組み合わせる。

data User = User { firstName :: Maybe String, lastName :: Maybe String } deriving Show

userName :: User -> Maybe String userName user = firstName user >>= \f -> lastName user >>= \l -> return $ f ++ " " ++ l

Page 13: MP in Haskell

同種のモナドを扱う場合

(3) do記法

モナドのためのシンタックスシュガーを活用する。

data User = User { firstName :: Maybe String, lastName :: Maybe String } deriving Show

userName :: User -> Maybe String userName user = do f <- firstName user l <- lastName user return $ f ++ " " ++ l

Page 14: MP in Haskell

異種のモナドが混在する場合

例えば、 Maybe と を組み合わせてEither

Either e (Maybe a) として扱う必要がある場合

Page 15: MP in Haskell

異種のモナドが混在する場合

(1) パターンマッチ

data User = User { id' :: Int, firstName :: Maybe String, lastName :: Maybe String } deriving Show

userRole :: Int -> Either Error Role userRole i = undefined

userInfo :: User -> Either Error (Maybe String) userInfo user = case userRole $ id' user of Right r -> case user of User {firstName = Just f, lastName = Just l} -> Right . Just $ f ++ " " ++ l ++ ": " ++ show r _ -> Right Nothing Left e -> Left e

Page 16: MP in Haskell

問題点

複数階層のモナドの分解・再構築が煩わしい構造に強く依存しているため変更に弱い

パターンマッチがネストして書きづらく読みづらい

Page 17: MP in Haskell

異種のモナドが混在する場合

(2) 高階関数

data User = User { id' :: Int, firstName :: Maybe String, lastName :: Maybe String } deriving Show

userRole :: Int -> Either Error Role userRole i = undefined

userInfo :: User -> Either Error (Maybe String) userInfo user = userRole (id' user) >>= \r -> return $ firstName user >>= \f -> lastName user >>= \l -> return $ f ++ " " ++ l ++ ": " ++ show r

Page 18: MP in Haskell

問題点

構造を直接扱う必要はないが関数がネストして書きづらく読みづらい

Page 19: MP in Haskell

異種のモナドが混在する場合

(3) do記法

data User = User { id' :: Int, firstName :: Maybe String, lastName :: Maybe String } deriving Show

userRole :: Int -> Either Error Role userRole i = undefined

userInfo :: User -> Either Error (Maybe String) userInfo user = do r <- userRole $ id' user return $ do f <- firstName user l <- lastName user return $ f ++ " " ++ l ++ ": " ++ show r

Page 20: MP in Haskell

問題点

関数はネストしないがdo記法が連鎖して書きづらく読みづらい

Page 21: MP in Haskell

モナド変換子(monad transformer)とは

一言で言えば、あるモナドに別のモナドを上乗せ(合成)したモナド。

ネストしたモナドをネストしていないかのように扱えるようになる。

e.g. , , MaybeTEitherTListT

Page 22: MP in Haskell

モナド変換子の生成と変換

-- M(モナド)とMaybeでネストしたモナド mMaybeA :: M (Maybe a) -- MaybeとMを合成したMaybeT maybeTMA :: MaybeT M a -- Maybe maybeA :: Maybe a -- M mA :: M a

-- M (Maybe a) → MaybeT M a MaybeT mMaybeA -- MaybeT M a → M (Maybe a) runMaybeT maybeTMA -- Maybe a → M (Maybe a) → MaybeT M a MaybeT $ return maybeA -- M a → MaybeT M a lift mA

Page 23: MP in Haskell

モナド変換子の導入

ここではモナド変換子 MaybeT を利用して

Maybe と Either を合成してみる。

Page 24: MP in Haskell

import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe

data User = User { id' :: Int, firstName :: Maybe String, lastName :: Maybe String } deriving Show

userRole :: Int -> Either Error Role userRole i = undefined

userInfo :: User -> Either Error (Maybe String) userInfo user = runMaybeT $ do r <- lift . userRole $ id' user f <- MaybeT . return $ firstName user l <- MaybeT . return $ lastName user return $ f ++ " " ++ l ++ ": " ++ show r

Page 25: MP in Haskell

Maybe a と Either e a をdo記法1つでシンプルに扱える

モナド変換子への変換がやや冗長

Page 26: MP in Haskell

さらにリファクタ

モナド変換子への変換を関数として抽出してみる。

Page 27: MP in Haskell

import Control.Monad.Trans.Class import Control.Monad.Trans.Maybe

data User = User { id' :: Int, firstName :: Maybe String, lastName :: Maybe String } deriving Show

userRole :: Int -> Either Error Role userRole i = undefined

fromMaybe :: Maybe a -> MaybeT (Either Error) a fromMaybe = MaybeT . return

userInfo :: User -> Either Error (Maybe String) userInfo user = runMaybeT $ do r <- lift . userRole $ id' user f <- fromMaybe $ firstName user l <- fromMaybe $ lastName user return $ f ++ " " ++ l ++ ": " ++ show r

Page 28: MP in Haskell

Further Reading

Functor, Applicative, Monadのシンプルな定式化 - Qiita

ScalaでFutureとEitherを組み合わせたときに綺麗に書く方法 - scalaとか・・・

Scalaz Monad Transformers - Underscore

独習 Scalaz — モナド変換子

Easy Monad

Haskell モナド変換子 超入門 - Qiita

All About Monads - Sampou.Org

Source CodeGist - lagenorhynque - monad-transformers