4

I'm having a problem with scala generics. While the first function I defined here seems to be perfectly ok, the compiler complains about the second definition with:

error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
    def >>[B](a: C[B])(implicit m: Monad[C]): C[B] = {
        ^

What am I doing wrong here?

   trait Lifter[C[_]] {
      implicit def liftToMonad[A](c: C[A]) = new {
        def >>=[B](f: A => C[B])(implicit m: Monad[C]): C[B] = { 
          m >>= (c, f)
        }   
        def >>[B](a: C[B])(implicit m: Monad[C]): C[B] = { 
          m >> a
        }   
      }
    }

IMPORTANT: This is NOT a question about Monads, it's a question about scala polymorphism in general.

EDIT: Here is my Monad definition

trait Monad[C[_]] {
  def >>=[A, B](a: C[A], f: A => C[B]): C[B]
  def >>=[B](a: C[B]): C[B]
  def apply[A](a: A): C[A]
}

BTW: I'm using scala 2.8RC1

Regards, raichoo

raichoo
  • 2,557
  • 21
  • 28
  • It would help if you had your definition of `Monad` here. The `Monad[C]` part looks suspicious (I would have thought `Monad[C[_]]` would be used), but it's hard to tell without knowing what `Monad` is. – Rex Kerr Apr 21 '10 at 19:16
  • The problem boils down to that `new { … }` produces an instance of an anonymous structural type. Scala has some limitations on how type parameters from outside can be used within structural types, to facilitate reflective method invocations. These limitations are somewhat stricter than necessary though (to err on the safe side). You can workaround the problem by simply replacing the anonymous structural type with a named local type, as shown in the answer. – Vladimir Reshetnikov Nov 30 '17 at 22:41

2 Answers2

10

Filling in the blanks in your example, I made this compile:

trait Monad[C[_]] {
  def >>=[A, B](f: A => C[B]): C[B]
  def >>[B](a: C[B]): C[B]
}

trait Lifter[C[_]] {
  class D {
    def >>=[A, B](f: A => C[B])(implicit m: Monad[C]): C[B] = {
      m >>= f
    }
    def >>[B](a: C[B])(implicit m: Monad[C]): C[B] = {
      m >> a
    }
  }

  implicit def liftToMonad[A](c: C[A]) = new D
}
Randall Schulz
  • 26,420
  • 4
  • 61
  • 81
0

Thanks, that really helped. Your answer pointed me into the right direction. I wrote the thing to this:

trait Lifter[C[_]] {
  class Wrapper[A](c: C[A])  {
    def >>=[B](f: A => C[B])(implicit m: Monad[C]): C[B] = { 
      m >>= (c, f)
    }   
    def >>[B](b: C[B])(implicit m: Monad[C]): C[B] = { 
      m >> (c, b)
    }   
  }

  implicit def liftToMonad[A](c: C[A]): Wrapper[A] = new Wrapper(c)
}

Thanks a lot.

Regards, raichoo

raichoo
  • 2,557
  • 21
  • 28