有一堆合法的半群实例Either
,其中哪些应该包含在 Cats 中是一些 争论的问题。Cats、Scalaz 和 Haskell 在这方面都做出了不同的选择,而您描述的实例(翻转但左右结合)与这三个不同,它没有我的特定名称我知道,它不是由 Cats 以任何名称或任何形式提供的。
这本身当然不是问题,因为正如我们将在下面看到的那样,很容易验证此实例是否合法,但是您应该注意一个潜在问题。您并没有真正解释您想要的语义,但是如果您想将其提升为 a ,那么当您同时拥有 a和 a时Monoid
选择 的事实意味着您的零必须是。如果您将权利视为成功而将左视为在组合值时可以安全忽略的错误,这可能有点奇怪。Right
Left
Right
Left
不过,您问的Semigroup
是 ,不是Monoid
,所以让我们暂时忽略它并表明这件事是合法的。首先是定义:
import cats.kernel.Semigroup
implicit def eitherSemigroup[A, B](implicit
A: Semigroup[A],
B: Semigroup[B]
): Semigroup[Either[A, B]] = Semigroup.instance {
case (Right(x), Right(y)) => Right(B.combine(x, y))
case (r @ Right(_), Left(_)) => r
case (Left(_), r @ Right(_)) => r
case (Left(x), Left(y)) => Left(A.combine(x, y))
}
然后是检查部分:
import cats.instances.int._
import cats.instances.string._
import cats.kernel.instances.either.catsStdEqForEither
import cats.kernel.laws.discipline.SemigroupTests
import org.scalacheck.Test.Parameters
SemigroupTests(eitherSemigroup[String, Int]).semigroup.all.check(Parameters.default)
是的,没关系:
+ semigroup.associative: OK, passed 100 tests.
+ semigroup.combineAllOption: OK, passed 100 tests.
+ semigroup.repeat1: OK, passed 100 tests.
+ semigroup.repeat2: OK, passed 100 tests.
就个人而言,如果我想要这样的东西,我可能会使用包装器来避免混淆我的代码的未来读者(包括我自己),但鉴于没有人真正知道半组Either
应该做什么,我不认为使用自定义实例是对于标准库中的大多数其他类型来说,这是一个大问题。