如何为Monad定义隐式转换器?

时间:2015-09-15 14:52:20

标签: scalaz

我正在定义一个具有抽象类型B的特征,我想将其用作monad。要指定B必须能够充当monad,我声明一个隐式的monadB

trait A {
  type B[_]
  implicit def monadB: Monad[B]
}

然后,当我实现此类型时,我将具体类型分配给B,例如List。然后,我需要为隐式monadB提供具体的定义。例如,在下面的函数.point[B]中调用方法randomDouble时需要它。我该怎么办?

trait A2 extends A { 
  type B[_] = List[_]
  implicit def monadB: Monad[B] = ???

  def randomDouble: B[Double] = new Random.nextDouble.point[B]
}

我试过了:

implicit def monadB: Monad[B] = implicitly[Monad[B]] 

但是这会在运行时卡在无限循环中,我想因为implicitly本身依赖于相应的隐式值。我想我需要说Monad[B]的隐含值实际上与Monad[List]的隐含值相同,因为B[_] = List[_]。但不幸的是,

implicit def monadB: Monad[B] = implicitly[Monad[List]]

也不起作用,因为Monad在它的类型参数中是不变的(如果我得到它,意味着Monad [List]不能用来代替Monad [B],即使B = List)

我被困住了。如何定义monadB

2 个答案:

答案 0 :(得分:1)

您可能还需要考虑另外两种方式:

你可以简单地拥有:

 def randomDouble[B[_]](implicit monadB: Monad[B]): B[Double] = (new Random).nextDouble.point[B]

然后你就可以这样使用它:println(randomDouble[List]),所以你不要将randomDouble绑定到任何特定的monad。

或者,如果你坚持使用特征:

      trait A {
        type B[_]
        implicit def monadB: Monad[B]
      }

      trait A2 extends A {
        def randomDouble: B[Double] = (new Random).nextDouble.point[B]
      }


      def a2[A[_]](implicit m: Monad[A]) = new A2 {
        type B[C] = A[C]
        implicit val monadB = m
      }

然后你使用它println(a2[List].randomDouble)再次将A2a2绑定到任何特定的monad。

答案 1 :(得分:0)

事实证明,使用符号指定内部抽象类型而不是保留_可以隐式使用[Monad [List]]:

trait A2 extends A { 
  type B[A] = List[A]
  implicit def monadB: Monad[B] = implicitly[Monad[List]]

  def randomDouble: B[Double] = new Random.nextDouble.point[B]
}

虽然它有效,但我没有任何解释原因。