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]
...
}
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. 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
f a
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. 同種のモナドを扱う場合
(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. 同種のモナドを扱う場合
(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
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
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
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
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
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
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