如何解释 fold 和 foldK 之间的区别?

How do I explain the difference between fold and foldK?

在刚学习函数式编程并完成在线Scala猫练习的程序员here的背景下,以下结果似乎令人费解:

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")
}

我可以按照 fold 的示例,但不能按照 foldK 的示例。 documentation for foldK 表示:

This method is identical to fold, except that we use the universal monoid (MonoidK[G]) to get a Monoid[G[A]] instance.

我不明白这种差异会如何导致上面看到的行为,其中列表中的第三个元素 (Option("three")) 是 "ignored" 对于 foldK.

有人可以解释一下吗?

fold 使用 Monoid[Option[A]] 实例,并且 cats/kernel/instances/option.scala 具有以下 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))
        }
    }

但是 foldK 想要一个 MoinoidK[Option] 实例,这个差异的答案是 combineKOption

的实现

如果您查看 cats.instances.OptionInstances,您会发现以下内容

  def combineK[A](x: Option[A], y: Option[A]): Option[A] = x orElse y

这应该是解释事情。我不知道这是有意为之还是只是被忽视的猫实例不一致的偏差。