1

Suppose I want to use implicitly to simplify the appearance of my code and I'm writing a function that needs to use a Monoid instance for one of the parameters, but the monoid is over a container type, such as A[B]. For example:

  trait Monoid[A] {
    def mappend(a1: A, a2: A): A
    def mzero: A
  }

  implicit def futureOfListMonoid[A] = new Monoid[Future[List[A]]] {
    def mappend(a1: Future[List[A]], a2: Future[List[A]]) = {
      for {
        v1 <- a1
        v2 <- a2
      } yield (v1 ++ v2)
    }
    def mzero = Future.successful(Nil)
  }

Suppose I want to write a generic function that operates over a generic monoid over a type container, such as in the following toy example:

  // this compiles and works, but isn't good enough
  // for my more complicated example, which need to
  // specify that A is a container type
  def myAppend[A: Monoid](a1: A, a2: A): A = {
    implicitly[Monoid[A]].mappend(a1, a2)
  }

  // this is roughly what I want, but it doesn't compile
  def myAppend[A[_]: Monoid, B](a1: A[B], a2: A[B]): A[B] = {
    implicitly[Monoid[A[B]]].mappend(a1, a2)
  }

Is there a way to make this work without using implicit parameters (I know this approach will work).

Editing to include a link to codereview.stackexchange of the more complicated example: https://codereview.stackexchange.com/questions/51571/custom-implementation-of-generic-future-sequence-in-scala

Community
  • 1
  • 1
jonderry
  • 23,013
  • 32
  • 104
  • 171
  • These things are compositional—you write an instance for `Future[A]` where `A` has a monoid instance, and one for `List[A]`, where `A` is any old `A`, and you get an instance for `Future[List[A]]` for free. – Travis Brown May 23 '14 at 06:44
  • That's interesting. I still can't seem to get the implicitly piece to work though (still getting complaints about taking type parameters when not supposed to or missing type parameters when needed, depending on the potential solution I'm trying). – jonderry May 23 '14 at 06:52
  • Not sure what you're trying, but don't aim for an implicit method that creates a `Monoid[Future[List[A]]]` directly. Have a `def futureMonoid[A: Monoid]: Monoid[Future[A]]` and a `def listMonoid[A]: Monoid[List[A]]`. – Travis Brown May 23 '14 at 06:55
  • Edited to include the more complicated example, note that I'm not sure how to use the `futureMonoid[A: Monoid]` syntax with more than one type either (e.g., `Monoid` and `Traversable`). – jonderry May 23 '14 at 07:03
  • If you want to take a look at the full code, I posted it on codereview.stackexchange (See above link). – jonderry May 23 '14 at 18:56

1 Answers1

0

Self-answering with links to material on more complicated usage of context bounds for the sake of anyone else who encounters such issues.

You can declare a type to have multiple context bounds: ":" in type parameter

But it seems you may not be able to use a context bound if the type itself takes multiple parameters: http://www.scala-lang.org/old/node/5310.html

However, by using type aliases with a higher kinded type you may by able to create context bounds for which the type accepts type parameters, at least in some cases: Context bounds shortcut with higher kinded-types

Please correct me if I'm wrong or out of date, or if Scala is updated with more support for this functionality.

Community
  • 1
  • 1
jonderry
  • 23,013
  • 32
  • 104
  • 171