2013-05-02 6 views
7

La definizione di opzione monoid del scalaz è la seguente:Perché l'implementazione di Monoid for Option di scalaz valuta la funzione f2 due volte?

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 è un passaggio per nome param che significa che ogni chiamata valutare l'espressione. Perché dovrebbe essere valutato di nuovo quando è stato appena valutato nel pattern match? Restituire Some(a2) dovrebbe essere lo stesso risultato e l'espressione f2 potrebbe essere molto costosa.

Mi manca qualcosa?

Scalaz's Option.scala source

+3

Probabilmente un riporto dal Haskell pensare in cui la definizione equivalente è a buon mercato? –

+0

Hai provato questo? Metti un po 'di println al suo interno e controlla. – Felix

+0

Sì, l'ho provato e il println è stato colpito due volte. Lo aggiusterò e invierò una richiesta pull a scalaz, credo. – coltfred

risposta

4

Sembra a me come è stato scritto per evidenziare la simmetria del problema e per chiarezza, non per la velocità. Non si può semplicemente abbandonare la pigrizia del secondo argomento dal momento che Semigroup lo definisce in questo modo, e in altri contesti volte la pigrizia del secondo argomento può essere essenziale. Per preservare la rappresentazione visiva della simmetria del problema, probabilmente si desidera aggiungere solo

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

o somesuch.

(sarebbe bello se con argomenti nome potrebbe essere chiamato pigro per loro Memoize automaticamente.)

+1

L'ho inviato come richiesta pull e l'hanno unito, ma anche la tua soluzione funzionava. https://github.com/scalaz/scalaz/pull/352 – coltfred

Problemi correlati