MP in Haskell

142 Views

May 28, 16

スライド概要

「MP in Scala」のスピンオフ(Haskell版)。
cf. Scala版: https://www.docswell.com/s/lagenorhynque/Z7VR8G-mp-in-scala

profile-image

「楽しく楽にcoolにsmartに」を理想とするprogrammer/philosopher/liberalist/realist。 好きな言語はClojure, Haskell, Python, English, français, русский。 読書、プログラミング、語学、法学、数学が大好き! イルカと海も大好き🐬

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

MP in Haskell

2.

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

3.

自己紹介

4.

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

5.
[beta]
モナド(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.

モナドの具体例 例えば、 Maybe。 型クラスFunctor, Applicative, Monadのインスタンスになっている。

7.

の fmap/ <$> Functor (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.

の <*> 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.

の >>= 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 fa 記法による実装

10.

同種のモナドを扱う場合 例えば、 Maybeを単独で使う場合

11.
[beta]
同種のモナドを扱う場合
(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.
[beta]
同種のモナドを扱う場合
(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.
[beta]
同種のモナドを扱う場合

記法

(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.

異種のモナドが混在する場合 例えば、 Maybeと Eitherを組み合わせて Either e (Maybe a)として扱う必要がある場合

15.
[beta]
異種のモナドが混在する場合
(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.

問題点 複数階層のモナドの分解・再構築が煩わしい 構造に強く依存しているため変更に弱い パターンマッチがネストして書きづらく読みづらい

17.
[beta]
異種のモナドが混在する場合
(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.

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

19.
[beta]
異種のモナドが混在する場合

記法

(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.

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

21.

モナド変換子(monad transformer)とは 一言で言えば、あるモナドに別のモナドを上乗せ(合成)したモナド。 ネストしたモナドをネストしていないかのように扱えるようになる。 e.g. MaybeT, EitherT, ListT

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.

モナド変換子の導入 ここではモナド変換子 MaybeTを利用して Maybeと Eitherを合成してみる。

24.
[beta]
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.

と Either e aをdo記法1つでシンプルに扱える モナド変換子への変換がやや冗長 Maybe a

26.

さらにリファクタ モナド変換子への変換を関数として抽出してみる。

27.
[beta]
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.

Further Reading のシンプルな定式化 - Qiita ScalaでFutureとEitherを組み合わせたときに綺麗に書く方法 - scala とか・・・ Functor, Applicative, Monad Scalaz Monad Transformers - Underscore 独習 Scalaz — モナド変換子 Easy Monad Haskell モナド変換子 超入門 - Qiita All About Monads - Sampou.Org Source Code Gist - lagenorhynque - monad-transformers