Upgrade to Pro — share decks privately, control downloads, hide ads and more …

MP in Scala

MP in Scala

Scalaでモナディックプログラミング!
cf. Haskell版: https://speakerdeck.com/lagenorhynque/mp-in-haskell

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

Kent OHASHI

May 27, 2016
Tweet

More Decks by Kent OHASHI

Other Decks in Programming

Transcript

  1. ( d e f p r o f i l

    e 大橋 賢人 [ O H A S H I K e n t ] : c o m p a n y 株式会社オプト テクノロジー 開発2部 : g i t h u b @ l a g e n o r h y n q u e : t w i t t e r @ l a g e n o r h y n q u e : l a n g u a g e s [ P y t h o n H a s k e l l C l o j u r e S c a l a E n g l i s h f r a n ç a i s D e u t s c h р у с с к и й ] : i n t e r e s t s [ プログラミング 語学 数学] )
  2. モナド(Monad) とは 一言で言えば、 f l a t M a p

    できる型クラス(type class)。 F[A] => (A => F[B]) => F[B] 型クラスFunctor, Applicative の上位互換。 / / s c a l a z . M o n a d t r a i t M o n a d [ F [ _ ] ] e x t e n d s A p p l i c a t i v e [ F ] w i t h B i n d [ F ] { a b s t r a c t d e f b i n d [ A , B ] ( f a : F [ A ] ) ( f : ( A ) ⇒ F [ B ] ) : F [ B ] a b s t r a c t d e f p o i n t [ A ] ( a : ⇒ A ) : F [ A ] . . . } - - H a s k e l l c l a s s A p p l i c a t i v e m = > M o n a d m w h e r e ( > > = ) : : f o r a l l a b . m a - > ( a - > m b ) - > m b r e t u r n : : a - > m a . . .
  3. Functor の m a p F[A] => (A => B)

    => F[B] にあたる。 s c a l a z . F u n c t o r . m a p v a l n : O p t i o n [ I n t ] = S o m e ( 1 ) v a l f : I n t = > S t r i n g = x = > x . t o S t r i n g / / O p t i o n # m a p n . m a p ( f ) / / O p t i o n # f l a t M a p による実装 n . f l a t M a p { a = > S o m e ( f ( a ) ) } / / f o r 式による実装 f o r { a < - n } y i e l d f ( a )
  4. Applicative の a p / < * > F[A] =>

    F[A => B] => F[B] , にあたる。 s c a l a z . A p p l y . a ps c a l a z . s y n t a x . A p p l y O p s . < * > v a l n : O p t i o n [ I n t ] = S o m e ( 1 ) v a l f : O p t i o n [ I n t = > S t r i n g ] = S o m e ( x = > x . t o S t r i n g ) / / O p t i o n # f l a t M a p , O p t i o n # m a p による実装 n . f l a t M a p { a = > f . m a p { g = > g ( a ) } } / / f o r 式による実装 f o r { a < - n g < - f } y i e l d g ( a )
  5. Monad の f l a t M a p /

    b i n d / > > = F[A] => (A => F[B]) => F[B] , にあたる。 s c a l a z . B i n d . b i n ds c a l a z . s y n t a x . B i n d O p s . > > = v a l n : O p t i o n [ I n t ] = S o m e ( 1 ) v a l f : I n t = > O p t i o n [ S t r i n g ] = x = > S o m e ( x . t o S t r i n g ) / / O p t i o n # f l a t M a p n . f l a t M a p ( f ) / / f o r 式による実装 f o r { a < - n b < - f ( a ) } y i e l d b
  6. 同種のモナドを扱う場合 (1) パター ンマッチ 構造に注目して分解(unapply, destructure) する。 c a s

    e c l a s s U s e r ( f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r N a m e ( u s e r : U s e r ) : O p t i o n [ S t r i n g ] = u s e r m a t c h { c a s e U s e r ( S o m e ( f i r s t ) , S o m e ( l a s t ) ) = > S o m e ( s " $ f i r s t $ l a s t " ) c a s e _ = > N o n e }
  7. 同種のモナドを扱う場合 (2) 高階関数 高階関数 m a p , f l

    a t M a p , etc. を組み合わせる。 c a s e c l a s s U s e r ( f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r N a m e ( u s e r : U s e r ) : O p t i o n [ S t r i n g ] = u s e r . f i r s t N a m e . f l a t M a p { f i r s t = > u s e r . l a s t N a m e . m a p { l a s t = > s " $ f i r s t $ l a s t " } }
  8. 同種のモナドを扱う場合 (3) f o r 式 モナドのためのシンタックスシュガー を活用する。 c a

    s e c l a s s U s e r ( f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r N a m e ( u s e r : U s e r ) : O p t i o n [ S t r i n g ] = f o r { f i r s t < - u s e r . f i r s t N a m e l a s t < - u s e r . l a s t N a m e } y i e l d s " $ f i r s t $ l a s t "
  9. 異種のモナドが混在する場合 例えば、 O p t i o n と を組み合わせて

    s c a l a z . \ / E \ / O p t i o n [ A ] として扱う必要がある場合
  10. 異種のモナドが混在する場合 (1) パター ンマッチ i m p o r t

    s c a l a z . _ , S c a l a z . _ c a s e c l a s s U s e r ( i d : I n t , f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r R o l e ( i d : I n t ) : E r r o r \ / R o l e = ? ? ? d e f u s e r I n f o ( u s e r : U s e r ) : E r r o r \ / O p t i o n [ S t r i n g ] = u s e r R o l e ( u s e r . i d ) m a t c h { c a s e \ / - ( r o l e ) = > u s e r m a t c h { c a s e U s e r ( _ , S o m e ( f i r s t ) , S o m e ( l a s t ) ) = > \ / - ( S o m e ( s " $ f i r s t $ l a s t : $ r o l e " ) ) c a s e _ = > \ / - ( N o n e ) } c a s e - \ / ( e r r o r ) = > - \ / ( e r r o r ) }
  11. 異種のモナドが混在する場合 (2) 高階関数 i m p o r t s

    c a l a z . _ , S c a l a z . _ c a s e c l a s s U s e r ( i d : I n t , f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r R o l e ( i d : I n t ) : E r r o r \ / R o l e = ? ? ? d e f u s e r I n f o ( u s e r : U s e r ) : E r r o r \ / O p t i o n [ S t r i n g ] = u s e r R o l e ( u s e r . i d ) . m a p { r o l e = > u s e r . f i r s t N a m e . f l a t M a p { f i r s t = > u s e r . l a s t N a m e . m a p { l a s t = > s " $ f i r s t $ l a s t : $ r o l e " } } }
  12. 異種のモナドが混在する場合 (3) f o r 式 i m p o

    r t s c a l a z . _ , S c a l a z . _ c a s e c l a s s U s e r ( i d : I n t , f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r R o l e ( i d : I n t ) : E r r o r \ / R o l e = ? ? ? d e f u s e r I n f o ( u s e r : U s e r ) : E r r o r \ / O p t i o n [ S t r i n g ] = f o r { r o l e < - u s e r R o l e ( u s e r . i d ) } y i e l d f o r { f i r s t < - u s e r . f i r s t N a m e l a s t < - u s e r . l a s t N a m e } y i e l d s " $ f i r s t $ l a s t : $ r o l e "
  13. モナド変換子の生成と変換 / / 型パラメー タを1 個とる型F ( モナド) t y

    p e F [ A ] = ? ? ? / / F とO p t i o n でネストしたモナド v a l f O p t i o n A : F [ O p t i o n [ A ] ] = ? ? ? / / O p t i o n とF を合成したO p t i o n T v a l o p t i o n T F A : O p t i o n T [ F , A ] = ? ? ? / / O p t i o n v a l o p t i o n A : O p t i o n [ A ] = ? ? ? / / F v a l f A : F [ A ] = ? ? ? / / F [ O p t i o n [ A ] ] → O p t i o n T [ F , A ] O p t i o n T . o p t i o n T ( f O p t i o n A ) / / O p t i o n T [ F , A ] → F [ O p t i o n [ A ] ] o p t i o n T F A . r u n / / O p t i o n [ A ] → F [ O p t i o n [ A ] ] → O p t i o n T [ F , A ] O p t i o n T . o p t i o n T ( o p t i o n A . p o i n t [ F ] ) / / F [ A ] → O p t i o n T [ F , A ] f A . l i f t M [ O p t i o n T ]
  14. モナド変換子の導入 ここではモナド変換子 s c a l a z . O

    p t i o n T を利用して O p t i o n と s c a l a z . \ / を合成してみる。
  15. i m p o r t s c a l

    a z . _ , S c a l a z . _ c a s e c l a s s U s e r ( i d : I n t , f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r R o l e ( i d : I n t ) : E r r o r \ / R o l e = ? ? ? t y p e E r r o r O r R e s u l t [ + A ] = E r r o r \ / A d e f u s e r I n f o ( u s e r : U s e r ) : E r r o r \ / O p t i o n [ S t r i n g ] = ( f o r { r o l e < - u s e r R o l e ( u s e r . i d ) . l i f t M [ O p t i o n T ] f i r s t < - O p t i o n T . o p t i o n T ( u s e r . f i r s t N a m e . p o i n t [ E r r o r O r R e s u l t ] ) l a s t < - O p t i o n T . o p t i o n T ( u s e r . l a s t N a m e . p o i n t [ E r r o r O r R e s u l t ] ) } y i e l d s " $ f i r s t $ l a s t : $ r o l e " ) . r u n
  16. O p t i o n [ + A ]

    と E \ / A をf o r 式1 つでシンプルに扱える モナド変換子への変換がやや冗長
  17. i m p o r t s c a l

    a z . _ , S c a l a z . _ c a s e c l a s s U s e r ( i d : I n t , f i r s t N a m e : O p t i o n [ S t r i n g ] , l a s t N a m e : O p t i o n [ S t r i n g ] ) d e f u s e r R o l e ( i d : I n t ) : E r r o r \ / R o l e = ? ? ? t y p e E r r o r O r R e s u l t [ + A ] = E r r o r \ / A d e f f r o m O p t i o n [ A ] ( a : O p t i o n [ A ] ) : O p t i o n T [ E r r o r O r R e s u l t , A ] = O p t i o n T . o p t i o n T ( a . p o i n t [ E r r o r O r R e s u l t ] ) d e f f r o m E i t h e r [ A ] ( a : E r r o r O r R e s u l t [ A ] ) : O p t i o n T [ E r r o r O r R e s u l t , A ] = a . l i f t M [ O p t i o n T ] d e f u s e r I n f o ( u s e r : U s e r ) : E r r o r \ / O p t i o n [ S t r i n g ] = ( f o r { r o l e < - u s e r R o l e ( u s e r . i d ) ▹ f r o m E i t h e r f i r s t < - u s e r . f i r s t N a m e ▹ f r o m O p t i o n l a s t < - u s e r . l a s t N a m e ▹ f r o m O p t i o n } y i e l d s " $ f i r s t $ l a s t : $ r o l e " ) . r u n
  18. ちなみに Q: このtype alias は何のためにあるのか? t y p e E

    r r o r O r R e s u l t [ + A ] = E r r o r \ / A A: モナド変換子の型パラメー タにカインド(kind) を合わせるため。
  19. 型 カインド O p t i o n T [

    F [ _ ] , A ] のF [ _ ] * - > * \ / [ + A , + B ] * - > * - > * / / 方法1 : t y p e a l i a s する t y p e E r r o r O r R e s u l t [ + A ] = E r r o r \ / A O p t i o n T [ E r r o r O r R e s u l t , A ] / / 方法2 : インラインでt y p e a l i a s する( t y p e l a m b d a ) O p t i o n T [ ( { t y p e λ [ + α ] = E r r o r \ / α } ) # λ , A ] / / 方法3 : コンパイラプラグインK i n d P r o j e c t o r を利用する O p t i o n T [ E r r o r \ / + ? , A ]
  20. 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