In the context of a programmer newly learning functional programming and completing the online Scala Exercises for Cats here, the following result seems puzzling:
import cats._
import cats.implicits._
object Foo {
def main(args: Array[String]): Unit =
println(Foldable[List].fold(List(None, Option("two"), Option("three"))))
//Some("twothree")
println(Foldable[List].foldK(List(None, Option("two"), Option("three"))))
//Some("two")
}
I can follow the example for fold
but not for foldK
. The documentation for foldK says:
This method is identical to fold, except that we use the universal monoid (
MonoidK[G]
) to get aMonoid[G[A]]
instance.
I don't understand how this difference would cause the behaviour seen above where somehow the third element in the list (Option("three")
) is "ignored" for the foldK
.
Can someone please explain?
fold
uses a Monoid[Option[A]] instance, and cats/kernel/instances/option.scala
has following implementation for Monoid[Option[A]].combine
,
def combine(x: Option[A], y: Option[A]): Option[A] =
x match {
case None => y
case Some(a) =>
y match {
case None => x
case Some(b) => Some(A.combine(a, b))
}
}
But foldK
wants a MoinoidK[Option]
instance and the answer for this difference is in implementation of combineK
for Option
,
If your look into cats.instances.OptionInstances
, you will find following
def combineK[A](x: Option[A], y: Option[A]): Option[A] = x orElse y
This should be explain things. I don't know if this is intended or just an overlooked deviation towards in-consistency in cats instances.