直接感想等をもらえてうれしかったです。
いつも御世話になっている皆さんに少しでも役に立つようがんばります。
Bind
今日はBindです。
Bindは型Z[_]を型パラメータにとり、型Z[A]と関数A => Z[B]を受け取り、Z[B]を返す関数bindを持ちます。
Haskellでは>>=にあたります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class ScalaChan[A](value: A) | |
implicit def ScalaChanEqual[A]: Equal[ScalaChan[A]] = equalA | |
implicit def ScalaChanShow[A]: Show[ScalaChan[A]] = showA | |
implicit lazy val ScalaChanFunctor: Functor[ScalaChan] = new Functor[ScalaChan] { | |
def fmap[A, B](a: ScalaChan[A], f: A => B): ScalaChan[B] = ScalaChan(f(a.value)) | |
} | |
implicit lazy val ScalaChanBind: Bind[ScalaChan] = new Bind[ScalaChan] { | |
def bind[A, B](a: ScalaChan[A], f: A => ScalaChan[B]): ScalaChan[B] = f(a.value) | |
} | |
lazy val scalaChan = for { | |
i <- ScalaChan(7) | |
s <- ScalaChan("Scalaz") | |
} yield s |+| i.shows | |
scalaChan assert_=== ScalaChan("Scalaz7") |
この例ではScalaChanFunctorとScalaChanBindを定義し、 MAに定義されたmap,flatMapが使えるようになったかを確認しました。
flatMap, >>=, >>=|, >|>
flatMapと>>=は同じ関数です。
>>=|と>|>も同じ関数です。
>>=|, >|> はflatMap, >>=と違い、内包していた値を捨て、値だけを渡します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List.fill(2, 2)(100).flatMap(1 +>: _) assert_=== List(1, 100, 100, 1, 100, 100) | |
(1.some.pure[Option] >>= (1 +>: _)) assert_=== 2.some | |
1.some.fpure[List] >>=| 2.some assert_=== 2.some | |
1.pure[Tuple1].fpure[List].fpure[Option] >|> none[Int].pure[Tuple1] assert_=== Tuple1(None) |
ちなみにflatMap, >>=の糖衣関数∗、>>=|, >|>の糖衣関数∗|が定義されています。
forever
使い方がよく分からない関数。
>|> を使い、foreverの結果を連結し続けます。
なので評価するとStackOverflowError必至だと思うのですが・・・
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
scala> try { ((_: Int) + 1).forever[Int].apply(1) } catch { case e => e } | |
res75: Any = java.lang.StackOverflowError | |
scala> try { 1.pure[Stream].forever[Stream[Int]] } catch { case e => e } | |
res76: java.lang.Object = java.lang.StackOverflowError |
join
型M[A]のAに、M[A]が適用されたM[M[A]]を連結し、M[A]を返します。
要は汎用的flatten。
糖衣関数にμがあります。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
List(3, 4, 6).replicate[List](2).join assert_=== List(3, 4, 6, 3, 4, 6) | |
lazy val f: Int => Int => Int = i => j => i |+| j | |
(f μ).apply(5) assert_=== 10 |
最後の例はjoinを行ったことにより、
(\a. (\b. a + b))
が
に変換されました。
値を適用すると、
(\a. (\b. a + b))(5)(5) ->
(\b. 5 + b)(5) ->
5 + 5 -> 10
となり、関数に値を2度適用する関数であることが分かります。
Bindはbindという1つの関数だけを持っていますが、それを定義するだけでこれだけのものが使えるようになります。
Scalazおそるべし・・・・!
※追記
joinのところの訂正
読み直したらとても違和感を感じたので、定義を読み直したら全然違ったという・・・
Predefの<:<が恒等関数のようなものを返すことは分かっていたのですが・・・・・
実際はこうなります。
(\r. (\f. (\t f(r(t))(t)))(\i. (\j. i + j)))(\x. x)(5)
(\f. (\t f((\x. x)(t))(t)))(\i. (\j. i + j))(5)
(\t (\i. (\j. i + j))((\x. x)(t))(t))(5)
(\i. (\j. i + j))((\x. x)(5))(5)
(\i. (\j. i + j))(5)(5)
(\j. 5 + j)(5)
5 + 5
10
0 件のコメント:
コメントを投稿