Lambdaカクテル

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

Invite link for Scalaわいわいランド

BがMonoidのとき、A => BもMonoidになる

ふと気になったけど今まで記事書いてなかったのでいちおう確かめることにした。

ある1引数関数f: A => Bがあったとする。

type A
type B
val f: A => B = ???

Bがモノイドであるとする。

implicit class BMonoid extends Monoid[B] {
  ...
}

このとき、1引数関数A => B(Function1[A, B])はモノイドになるだろうか?

なります

結論から言うと、モノイドになる。

これは、cats.kernel.instances.Function1Monoidが定義されているため。

www.javadoc.io

final private[instances] case class CombineFunction1[A, B](left: A => B, right: A => B, semiB: Semigroup[B])
    extends (A => B) {
  private def call(fn: A => B, a: A): TailRec[B] =
    fn match {
      case ref: CombineFunction1[A, B] @unchecked =>
        for {
          lb <- tailcall(call(ref.left, a))
          rb <- tailcall(call(ref.right, a))
        } yield ref.semiB.combine(lb, rb)
      case _ => done(fn(a))
    }

  final override def apply(a: A): B = call(this, a).result
}

trait Function1Semigroup[A, B] extends Semigroup[A => B] {
  implicit def B: Semigroup[B]

  override def combine(x: A => B, y: A => B): A => B =
    CombineFunction1(x, y, B)

  override def combineAllOption(fns: IterableOnce[A => B]): Option[A => B] =
    if (fns.iterator.isEmpty) None
    else
      Some { (a: A) =>
        B.combineAllOption(fns.iterator.map(_.apply(a))).get
      }
}

trait Function1Monoid[A, B] extends Function1Semigroup[A, B] with Monoid[A => B] {
  implicit def B: Monoid[B]

  val empty: A => B =
    (_: A) => B.empty
}

要するに、同じ引数を渡して、その結果はモノイドなのでcombineする、というだけ。

github.com

振る舞いとしても自然だし、なにかと役立つだろう。

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