为什么scalaz';选项的幺半群的实现对f2函数求值两次?

为什么scalaz';选项的幺半群的实现对f2函数求值两次?,scala,scalaz,scalaz7,Scala,Scalaz,Scalaz7,scalaz选项幺半群的定义如下: implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = new Monoid[Option[A]] { def append(f1: Option[A], f2: => Option[A]) = (f1, f2) match { case (Some(a1), Some(a2)) => Some(Semigroup[A].append(a1, a2)) case

scalaz选项幺半群的定义如下:

implicit def optionMonoid[A: Semigroup]: Monoid[Option[A]] = new Monoid[Option[A]] {
  def append(f1: Option[A], f2: => Option[A]) = (f1, f2) match {
    case (Some(a1), Some(a2)) => Some(Semigroup[A].append(a1, a2))
    case (Some(a1), None)     => f1
    case (None, Some(a2))     => f2
    case (None, None)         => None
  }

  def zero: Option[A] = None
}
f2
是一个按名称传递的参数,这意味着每次调用都将对表达式求值。在模式匹配中刚刚评估时,为什么要再次评估它?返回
Some(a2)
应该是相同的结果,表达式
f2
可能非常昂贵

我错过什么了吗


在我看来,这篇文章是为了强调问题的对称性,为了清晰,而不是为了速度。您不能仅仅删除第二个参数的惰性,因为
半群
就是这样定义的,在其他上下文中,第二个参数的惰性可能是必不可少的。要保留问题对称性的视觉表示,您可能只需要添加

val g2 = f2  // Force evaluation
(f1, g2) match { ...
或者类似的


(如果可以将按名称命名的参数称为lazy来自动记忆它们,那就太好了。)

可能是Haskell思想中的一个遗留问题,在那里等价的定义比较便宜?您测试过吗?在里面放一些println然后检查。是的,我做了测试,println被击中了两次。我想我会修复它并向scalaz提交一个拉请求。我将它作为拉请求提交,他们将其合并,但您的解决方案也会起作用。