2017-04-20 1 views
1

Disons que j'ai un trait Monoid comme ci-dessous:Scala Monoid Combinator pour les options

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

Maintenant, si je veux écrire un optionMonoid pour cela, je pourrais l'écrire comme ceci:

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

Ceci étant donné le fait que je ne sais rien du type interne de l'Option. Mais que se passe-t-il si je veux avoir l'opérateur de la moissonneuse de telle manière que je veux vraiment combiner les types internes dans l'Option?

+0

Si vous voulez «mapper» sur les valeurs de 'Option', vous aurez besoin d'une instance de Functor. –

+0

Mais attendez, une instance de Functor ne changerait-elle pas mon type contenu dans l'Option? – sparkr

+0

Même si j'ai une instance de Functor, je ne sais toujours pas quel est mon type A pour pouvoir appliquer l'opérateur de la moissonneuse sur mon Type A! – sparkr

Répondre

5

Une 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 
} 

Il est facile de vérifier les lois de monoïdes détiennent.

+0

'def identity = None' Comment cela se passe-t-il dans le cas' Some'? –

+0

Donc, ici l'opérateur comine fonctionne pour n'importe quelle instance de Semigroup visible dans la portée! ° – sparkr

+0

@sparkr C'est comme j'ai commenté ci-dessus. Vous avez besoin du type contenu dans la boîte ('A') pour avoir aussi des propriétés monoïdales. –