Scala: тип параметра в уточнении структуры не может ссылаться на абстрактный тип, определенный вне этого уточнения.

У меня проблема с дженериками scala. В то время как первая функция, которую я определил здесь, выглядит совершенно нормально, компилятор жалуется на второе определение:

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] = {
        ^

Что я здесь делаю неправильно?

   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
        }   
      }
    }

ВАЖНО: это НЕ вопрос о монадах, это вопрос о полиморфизме scala в целом.

РЕДАКТИРОВАТЬ: вот мое определение монады

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]
}

Кстати: я использую scala 2.8RC1

С уважением, Райчу


person raichoo    schedule 21.04.2010    source источник
comment
Было бы полезно, если бы у вас было свое определение Monad здесь. Часть Monad[C] выглядит подозрительно (я бы подумал, что будет использоваться Monad[C[_]]), но трудно сказать, не зная, что такое Monad.   -  person Rex Kerr    schedule 21.04.2010
comment
Проблема сводится к тому, что new { … } создает экземпляр анонимного структурного типа. Scala имеет некоторые ограничения на то, как параметры типа извне могут использоваться внутри структурных типов, чтобы облегчить вызовы рефлексивных методов. Эти ограничения несколько строже, чем необходимо (чтобы ошибиться на всякий случай). Вы можете обойти эту проблему, просто заменив анонимный структурный тип именованным локальным типом, как показано в ответе.   -  person Vladimir Reshetnikov    schedule 01.12.2017


Ответы (2)


Заполнив пробелы в вашем примере, я сделал эту компиляцию:

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
}
person Randall Schulz    schedule 21.04.2010

Спасибо, это действительно помогло. Ваш ответ указал мне правильное направление. Я написал это:

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)
}

Большое спасибо.

С уважением, Райчу

person raichoo    schedule 21.04.2010