0

I'm defining a trait which has an abstract type B which I want to use as a monad. To specify that B must be able to act as a monad, I declare an implicit monadB:

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

Then, when I implement this type, I assign a concrete type to B, such as List. I then need to provide a concrete definition for the implicit monadB. It is needed, for example, when calling the method .point[B] in the function randomDouble below. How can I do it?

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

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

I've tried:

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

but this gets stuck in a infinite loop at runtime, I suppose because implicitly itself relies on an the corresponding implicit value. I guess I need to say that the implicit value for Monad[B] is actually the same as the implicit value for Monad[List], since B[_] = List[_]. But unfortunately,

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

doesn't work either, because Monad is invariant in it's type parameter (which, if I get it, means that Monad[List] can't be used in place of Monad[B], even though B = List).

I'm stuck. How do I define monadB?

Guillaume Chérel
  • 1,478
  • 8
  • 17

2 Answers2

1

There are two other ways that you might want to consider:

You can simply have:

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

and then you can use it like that: println(randomDouble[List]), so you don't tie randomDouble to any specific monad.

Alternatively, if you insist on using traits:

      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
      }

and then you use it println(a2[List].randomDouble) and again you don't tie A2 nor a2 to any specific monad.

mjaskowski
  • 1,479
  • 1
  • 12
  • 16
  • I my particular case, I actually want a function to be tied to a particular monad, because I use this function to extract the value inside the monad. It seems to me that extraction cannot be made generic. But your suggestion seem more generic and I probably could redesign my code to make it more like you suggest. – Guillaume Chérel Oct 05 '15 at 09:55
  • I call it scalaz style :) What do you mean by extracting value inside a monad? Would you mind giving an example ? – mjaskowski Oct 06 '15 at 10:46
  • For example, trait A declares a function that takes a monadic value and returns just a value: `def unwrap[A](x: F[A]): A`. F could be a state monad and you'd want `unwrap` to return just the result (without the state), or F could be a list and you could want to return the average of all of its elements. The action that `unwrap` performs depends on what F is. Thus, when you define `unwrap` in A2, you have to know what F is. So, `unwrap` must be tied to a specific monad (State, List, ...). Or is there another way? – Guillaume Chérel Oct 06 '15 at 20:12
  • First of all, you might want to check the Monad Transformers out (e.g. EitherT, ListT, OptionT). Alternatively, you might want to use the "pimp my library" pattern to induce the unwrap functionality on top monads you are interested in. – mjaskowski Oct 06 '15 at 23:06
0

It turns out that specifying the internal abstract type with a symbol rather than leaving a _ makes it possible to use implicitly[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]
}

While it works, I don't have any explanation as of why.

Guillaume Chérel
  • 1,478
  • 8
  • 17