2010-10-03 64 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