2013-05-02 5 views
7

次のようにscalazのオプションモノイドの定義は次のとおりです。scalazのOption for Monoidの実装がf2関数を2回評価するのはなぜですか?

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は、各呼び出しが式を評価することを意味名前のparamによってパスです。なぜそれがパターンマッチで評価されただけで再び評価されるべきですか?返信Some(a2)は同じ結果になり、式f2は非常に高価になる可能性があります。

何か不足していますか?

Scalaz's Option.scala source

+3

同等の定義が安いですおそらくHaskellのからのキャリーオーバーが考えて? –

+0

これはテストしましたか?その中にprintlnを入れて確認してください。 – Felix

+0

はい私はそれをテストし、printlnは2回ヒットしました。私はそれを修正し、私が推測するスカラズにプルリクエストを提出します。 – coltfred

答えて

4

それが問題の対称性を強調するために書かれており、明確にするためではなく、スピードのためだったようにそれは私に見えます。 Semigroupはそれをそのように定義しているので、第2引数の怠惰を落とすことはできません。他の文脈では、第2引数の怠惰が不可欠かもしれません。問題の対称性を視覚的に表現するために、

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

などを追加するだけです。

(自動的にmemoizeする怠惰ともいえる名引数であればそれはいいだろう。)

+1

私はプルリクエストとして提出し、それらをマージしましたが、あなたのソリューションも同様に機能します。 https://github.com/scalaz/scalaz/pull/352 – coltfred

関連する問題