2010-10-03 70 views
4

在Scala中,重载和隐式参数解析的交互似乎使得不可能使下面的代码可用。我该如何解决Scala中重载分辨率的限制?

trait Bijection[A, B] extends Function1[A, B] with Unapply[A, B] { self => 
    def apply(a: A): B 
    def unapply(b: B): A 
} 

sealed trait Unapply[A, B] { 
    def unapply(b: B): A 
} 

object Bijection { 
    implicit def biject[A](a: A): Biject[A] = new Biject(a) 

    implicit object IntStringBijection extends Bijection[Int, String] { 
    override def apply(a: Int): String = a.toString 
    override def unapply(b: String): Int = b.toInt 
    } 
} 

sealed class Biject[A](a: A) { 
    def as[B](implicit f: Function1[A, B]): B = f(a) 
    def as[B](implicit f: Unapply[B, A]): B = f unapply a 
} 

的这里的目标是为a.as [B],以不管执行的类型安全转换是否一个双射[A,B]或双射[B,A]是在隐式范围可用。

这不起作用的原因是隐式解析似乎发生在编译器的重载消歧之后,并且由于'as'的两个实现都具有相同的结果类型,所以编译器甚至没有考虑到试图找出是否有适当的隐含在可以执行转换的范围内。简而言之,隐式解析不用于重载消歧。

我希望有'as'重载的原因是为了避免需要该库的用户需要在呼叫站点编码双向注射的“方向”明明一个可以实现Biject就象这样:

sealed class Biject[A](a: A) { 
    def viaForward[B](implicit f: Function1[A, B]): B = f(a) 
    def viaReverse[B](implicit f: Unapply[B, A]): B = f unapply a 
} 

但是这是真的,因为没有吸引力它本质使得皮条客多余的;人们可能会明确地通过双射,但是当然你失去了使用双射的能力根据范围而变化。

这个问题有什么好的解决办法吗?

回答

5

这是怎么回事?

trait Bijection[A, B] extends Function1[A, B] with Unapply[A, B] { 
    self => 
    def apply(a: A): B 

    def unapply(b: B): A 
} 

sealed trait Unapply[A, B] { 
    def unapply(b: B): A 
} 

object Bijection { 
    implicit def biject[A](a: A): Biject[A] = new Biject(a) 

    implicit object IntStringBijection extends Bijection[Int, String] { 
    override def apply(a: Int): String = a.toString 

    override def unapply(b: String): Int = b.toInt 
    } 
} 

sealed class Biject[A](a: A) { 
    def as[B](implicit f: Either[Bijection[A, B], Bijection[B, A]]): B = f.fold(_ apply a, _ unapply a) 
} 

trait EitherLow { 
    implicit def left[A, B](implicit a: A): Either[A, B] = Left(a) 
} 

object Either extends EitherLow { 
    implicit def right[A, B](implicit b: B): Either[A, B] = Right(b) 
} 

import Bijection._ 
import Either._ 

1.as[String] 
"1".as[Int] 
+0

这是真棒,retrony,谢谢!我想到了它可能需要扮演一个角色,但我从来没有想到将双射投影本身投射到任一空间。如果我正确地理解了这一点,那么工作原因就是我最初的尝试没有做到的原因:在将参数隐式解析为“as”之前,对Biject的初始隐式转换是“完整的”,这使得左右两侧隐式转换以应用。 – 2010-10-03 19:04:54

+0

这个关键是使用隐式优先级来避免'1.as [Int]情况下的歧义。 – retronym 2010-10-03 19:12:44

+0

看来,即使没有低优先级隐含技巧,它也可以工作。可以在Bijection对象中声明left()和right()(并且它们可以是专用的,以便它们仅适用于Bijection实例),它仍然有效。 – 2010-10-03 20:31:35