Search code examples
scalascala-cats

How do I explain the difference between fold and foldK?


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 a Monoid[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?


Solution

  • 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.