Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

Scala: CatsのArrowを覚えたのでfizzbuzzにする

とりあえず何かを覚えたらfizzbuzzにするクセやめたい

import cats.syntax.all._
import cats.implicits._

extension (d: Int) def ~>(s: String)(n: Int) = (n % d == 0).guard[Option] as s
val fizzbuzz = (((2 ~> "fizz" &&& 3 ~> "buzz") >>> (_.toList.combineAll)) &&& (_.toString)) >>> { case (fb, n) => fb.getOrElse(n) }

1 to 50 map fizzbuzz

Arrowを使うと直線的に処理が記述できてありがたい感じがする。1ツイートにも収まるし。

要素

extension (d: Int) def ~>(s: String)(n: Int) = (n % d == 0).guard[Option] as s

extension method

extension (d: Int) def ~>(s: String)で、 d ~> s という表現が可能になる。Scala3テク。

(n: Int) = (n % d == 0).guard[Option] as s

関数を返したいので、extension defの引数をもう一つつけてある。

guardはcatsがBooleanに生やしてくれるメソッドで、b.guard[Option]と書くと

b match {
  case true => Some(true)
  case false => None
}

と同じ。

asは内容を破棄して指定した値を使わせるメソッド。a as bと書くとa.map(_ => b)と同じ。

総合すると、2 ~> "foo"と書くと、Int => Option[String]を返してくれる。そして、渡された値が2で割れる場合にのみSome("foo")が返るようになる。

val fizzbuzz = (((2 ~> "fizz" &&& 3 ~> "buzz") >>> (_.toList.combineAll)) &&& (_.toString)) >>> { case (fb, n) => fb.getOrElse(n) }

後半。

2 ~> "fizz" &&& 3 ~> "buzz"

2つの関数をArrowのパワーで並列に結合する。&&&は別名mergeで、A => BA => Cを受け取るとA => (B, C)にしてくれる。この場合はInt => (Option[String], Option[String])が得られる。

>>> (_.toList.combineAll)

>>>andThenのエイリアス。

_.toList.combineAll の型を明示すると(pair: (Option[String], Option[String])) => pair.toList.combineAllになっている。pair.toListによってList[Option[String]]に変換されるので、これをcombineAll`している。

知っていましたか?Stringはモノイドになります。そして、Option[String]も自動的にモノイドになるんですね。便利。そんで、モノイドのリストはcombineAllするとx1 |+| x2 |+| x3 |+| ... |+| xnの形で畳み込まれる。結果として、以下のような感じになる:

  • (None, None)None
  • (Some("fizz"), None)Some("fizz")
  • (None, Some("buzz"))Some("buzz")
  • (Some("fizz"), Some("buzz"))Some("fizzbuzz")

&&& (_.toString)

((2 ~> "fizz" &&& 3 ~> "buzz") >>> (_.toList.combineAll))の型はInt => Option[String]になっている。さらにここにmergeして、(_.toString)、つまりInt => Stringをくっつけている。

型はInt => (Option[String], String)になる。

>>> { case (fb, n) => fb.getOrElse(n) }

ここまで来れば説明不要でしょう。

汚い図ですが、このような処理を合成しているわけですね。

関連記事

blog.3qe.us

blog.3qe.us

blog.3qe.us

こいつずっとfizzbuzz書いてんな

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?