Перегрузка общих неявных преобразований

У меня небольшая проблема со scala (версия 2.8.0RC1) с неявными преобразованиями. Всякий раз, когда импортируется более одного неявного преобразования, первое из них затеняется. Вот код, в котором проявляется проблема:

// containers
class Maybe[T]
case class Nothing[T]() extends Maybe[T]
case class Just[T](value: T) extends Maybe[T]

case class Value[T](value: T)

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

// implicit converter
trait Extender[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, { (x: A) => b } )
    }
  }

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

// instance maybe
object maybemonad extends Extender[Maybe] {
  implicit object MaybeMonad extends Monad[Maybe] {
    override def >>=[A, B](a: Maybe[A], f: A => Maybe[B]): Maybe[B] = {
      a match {
        case Just(x) => f(x)
        case Nothing() => Nothing()
      }
    }

    override def pure[A](a: A): Maybe[A] = Just(a)
  }
}

// instance value
object identitymonad extends Extender[Value] {
  implicit object IdentityMonad extends Monad[Value] {
    override def >>=[A, B](a: Value[A], f: A => Value[B]): Value[B] = {
      a match {
        case Value(x) => f(x)
      }
    }

    override def pure[A](a: A): Value[A] = Value(a)
  }
}

import maybemonad._
//import identitymonad._

object Main {
  def main(args: Array[String]): Unit = {
    println(Just(1) >>= { (x: Int) => MaybeMonad.pure(x) })
  }
}

При раскомментировании второго оператора импорта все идет не так, поскольку первый «extendToMonad» затенен.

Однако этот работает:

object Main {
  implicit def foo(a: Int) = new  {
    def foobar(): Unit = { 
      println("Foobar")
    }   
  }

  implicit def foo(a: String) = new  {
    def foobar(): Unit = { 
      println(a)
    }   
  }

  def main(args: Array[String]): Unit = { 
    1 foobar()
    "bla" foobar()
  }
}

Итак, где подвох? Что мне не хватает?

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


person raichoo    schedule 25.04.2010    source источник
comment
Примечание: я думаю, что Nothing должен быть объектом case, расширяющим Maybe. Также вам следует подумать о выборе другого имени для этого объекта case, поскольку Nothing уже определен как подтип всех типов.   -  person missingfaktor    schedule 25.04.2010
comment
Как насчет case object None extends Maybe[Nothing]? None тоже уже используется в стандартной библиотеке (точно для той же цели).   -  person missingfaktor    schedule 25.04.2010
comment
Я должен упомянуть, что этот код никогда не будет запущен в производство. Это просто тестовый пример для меня, чтобы понять некоторые концепции Scala;)   -  person raichoo    schedule 26.04.2010
comment
Тем не менее, эти моменты заслуживают внимания, ИМО. :)   -  person missingfaktor    schedule 26.04.2010
comment
Можно ли продемонстрировать проблему в более коротком фрагменте кода?   -  person Seth Tisue    schedule 26.04.2010


Ответы (2)


Действительно, привязки и импортированные привязки скрыты по имени. Это в равной степени относится и к импортированным неявным преобразованиям.

Я считаю, что вы могли бы переименовать во время импорта в качестве обходного пути:

import IdentityMonad.{extendToMonad => extendToMonadIdentity}
import MaybeMonad.{extendToMonad => extendToMonadMaybe}

Вы можете взглянуть на Scalaz, в частности на scalaz.{Functor, Scalaz, MA}, чтобы узнать о другом способе кодирования этих классов типов. В частности, при поиске класса типов Monad[X] выполняется поиск объекта-компаньона Monad.

person retronym    schedule 26.04.2010
comment
Идея с переименованием звучала неплохо, но после этого scala не найдет оба имплицита. - person raichoo; 26.04.2010

я предполагаю, что компилятор считает

implicit object IdentityMonad extends Monad[Value] 

более конкретно, чем

implicit object MaybeMonad extends Monad[Maybe]

как часть процесса разрешения. Даниэль опубликовал статью, посвященную этому вопросу здесь< /а>. В вашем втором примере вызовы разрешают неявное непосредственно по типу, и указанное выше правило разрешения не требуется.

person Don Mackenzie    schedule 26.04.2010