Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

MP in Haskell

362 views

Published on

「MP in Scala」のスピンオフ(Haskell版)。
cf. http://www.slideshare.net/KentOhashi/mp-in-scala

Haskellでもモナディックプログラミング!

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

Published in: Software
  • Be the first to comment

  • Be the first to like this

MP in Haskell

  1. 1. MP in Haskell
  2. 2. MP = Monadic Programming 1. モナドとは何か 2. モナドの基本的な扱い方 3. モナド変換子の使い方
  3. 3. 自己紹介
  4. 4. (defprofile 大橋 賢人 [OHASHI Kent] :company 株式会社オプト テクノロジー開発2部 :github @lagenorhynque :twitter @lagenorhynque :languages [Python Haskell Clojure Scala English français Deutsch русский] :interests [プログラミング 語学 数学])
  5. 5. モナド(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] ... }
  6. 6. モナドの具体例 例えば、 。Maybe 型クラスFunctor, Applicative, Monadのインスタンスになっている。
  7. 7. 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
  8. 8. 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
  9. 9. 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
  10. 10. 同種のモナドを扱う場合 例えば、 Maybeを単独で使う場合
  11. 11. 同種のモナドを扱う場合 (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
  12. 12. 同種のモナドを扱う場合 (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
  13. 13. 同種のモナドを扱う場合 (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
  14. 14. 異種のモナドが混在する場合 例えば、 Maybeと を組み合わせてEither Either e (Maybe a)として扱う必要がある場合
  15. 15. 異種のモナドが混在する場合 (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
  16. 16. 問題点 複数階層のモナドの分解・再構築が煩わしい 構造に強く依存しているため変更に弱い パターンマッチがネストして書きづらく読みづらい
  17. 17. 異種のモナドが混在する場合 (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
  18. 18. 問題点 構造を直接扱う必要はないが関数がネストして書きづらく読みづらい
  19. 19. 異種のモナドが混在する場合 (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
  20. 20. 問題点 関数はネストしないがdo記法が連鎖して書きづらく読みづらい
  21. 21. モナド変換子(monad transformer)とは 一言で言えば、あるモナドに別のモナドを上乗せ(合成)したモナド。 ネストしたモナドをネストしていないかのように扱えるようになる。 e.g. , ,MaybeTEitherTListT
  22. 22. モナド変換子の生成と変換 -- 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
  23. 23. モナド変換子の導入 ここではモナド変換子MaybeTを利用して MaybeとEitherを合成してみる。
  24. 24. 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
  25. 25. Maybe aとEither e aをdo記法1つでシンプルに扱える モナド変換子への変換がやや冗長
  26. 26. さらにリファクタ モナド変換子への変換を関数として抽出してみる。
  27. 27. 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
  28. 28. 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 Code Gist - lagenorhynque - monad-transformers

×