2017-04-20 1 views
1

Lasst uns sagen, dass ich ein Monoid Eigenschaft haben, wie unten:Scala Monoid Combinator für Optionen

trait Monoid[A] { 
    def combine(a1: A, a2: A): A 
    def identity: A 
} 

Nun, wenn ich einen optionMonoid dafür schreiben wollen, könnte ich es so schreiben:

val optionMonoid1 = new Monoid[Option[A]] { 
    def combine(a1: Option[A], a2: Option[A2]) a1 orElse a2 
    def identity = None 
} 

Dies angesichts der Tatsache, dass ich nichts über den inneren Typ in der Option weiß. Aber was, wenn ich den Mähdrescher-Operator so haben möchte, dass ich die inneren Typen in der Option wirklich kombinieren möchte?

+0

Wenn Sie die Werte innerhalb der Option "abbilden" möchten, benötigen Sie eine Functor-Instanz. –

+0

Aber halt, würde eine Funktor-Instanz nicht meinen Typ ändern, der in der Option enthalten ist? – sparkr

+0

Auch wenn ich eine Functor-Instanz habe, weiß ich immer noch nicht, welcher Typ mein A ist, damit ich den Kombinator-Operator auf meinem Typ A anwenden kann! – sparkr

Antwort

5

Eine Option:

trait Semigroup[A] { 
    def combine(a1: A, a2: A): A 
} 

trait Monoid[A] extends Semigroup[A] { 
    def identity: A 
} 

def optionMonoid2[A](implicit sgA: Semigroup[A]) = new Monoid[Option[A]] { 
    def combine(a1: Option[A], a2: Option[A2]) = (a1, a2) match { 
    case (Some(b1), Some(b2)) => Some(sgA.combine(b1, b2)) 
    case _ => a1.orElse(a2) 
    } 
    def identity = None 
} 

Es ist einfach Monoid Gesetze halten zu überprüfen.

+0

'def identity = None' Wie gilt das für den Fall' Some'? –

+0

Also hier funktioniert der Comine-Operator für jede Semigroup-Instanz, die im Scope sichtbar ist! ° – sparkr

+0

@sparkr Es ist wie ich oben erwähnt habe. Sie benötigen den in der Box enthaltenen Typ ('A'), um auch monoidale Eigenschaften zu haben. –