2017-04-20 51 views
1

比方说,我有如下一个Monoid特点:斯卡拉含半幺群Combinator的对期权

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

现在,如果我想要写这个的optionMonoid,我可以写这样的:

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

这给了我一个事实,即对Option中的内部类型一无所知。但是如果我想以这样的方式组合运算符,那么我想要真正地将Option中的内部类型组合起来呢?

+0

如果你想'映射'在'Option'里面的值,你需要一个Functor实例。 –

+0

但是请等一下,Functor实例是否会更改我的Option中包含的类型? – sparkr

+0

即使我有一个Functor实例,我仍然不知道我的A的类型是什么,所以我可以在我的A类上应用组合运算符! – sparkr

回答

5

一个选项:

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 
} 

很容易验证独异的法律持有。

+0

'def identity = None'这对于'Some'情况怎么样? –

+0

所以这里的comine操作符适用于在示波器中可见的任何Semigroup实例!° – sparkr

+0

@sparkr正如我以上评论过的那样。你需要包含在框中的类型('A')也具有monoidal属性。 –