Почему реализация Monaz for Option в Скалазе дважды оценивает функцию f2?

Определение опции моноида скаляза следующее:

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 может быть очень дорогим.

Я что-то пропустил?

Источник Скалаза Option.scala

1 ответ

Решение

Мне кажется, что это было написано, чтобы подчеркнуть симметрию проблемы и для ясности, а не для скорости. Вы не можете просто отбросить лень второго аргумента, так как Semigroup определяет это таким образом, и в других случаях лень второго аргумента может быть существенной. Чтобы сохранить визуальное представление симметрии задачи, вы, вероятно, хотите просто добавить

val g2 = f2  // Force evaluation
(f1, g2) match { ...

или что-то подобное.

(Было бы хорошо, если бы аргументы по имени назывались ленивыми, чтобы автоматически их запоминать.)

Другие вопросы по тегам