2010-04-25 51 views
3

我有隱式轉換的小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) }) 
    } 
} 

當取消對第二import語句的一切,因爲第一個「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() 
    } 
} 

所以,在這裏收穫?我錯過了什麼?

問候, raichoo

+3

旁白:我認爲'Nothing'應該是一個延伸'Maybe'的案例對象。你也應該考慮爲這個case對象選擇一個不同的名字,因爲'Nothing'已經被定義爲所有類型的子類型。 – missingfaktor 2010-04-25 19:53:40

+1

'case對象無延伸可能[Nothing]'? 'None'也已經在標準庫中使用過(爲了完全相同的目的)。 – missingfaktor 2010-04-25 19:56:41

+0

我應該提到這個代碼永遠不會投入生產。這只是我自己想出的一些scala概念的測試用例;) – raichoo 2010-04-25 20:26:40

回答

0

我的猜測是,編譯器對於

implicit object IdentityMonad extends Monad[Value] 

更具體的比

implicit object MaybeMonad extends Monad[Maybe] 

隨着分辨率的過程的一部分。有一篇由丹尼爾發表的文章,涵蓋了這個問題here。在第二個示例中,這些調用直接按類型來解析隱式,並且上述解析規則不是必需的。

1

事實上,綁定和導入的綁定是按名稱進行映射的。這同樣適用於導入的隱式轉換。

我相信你可以在進口作爲一種解決方法中重命名:

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

你可能喜歡看Scalaz,尤其scalaz.{Functor, Scalaz, MA}另一種方式來編碼這些類型的類。特別是,當搜索類型類別Monad[X]時,搜索伴侶對象Monad

+0

重命名的想法聽起來不錯,但斯卡拉之後不會發現兩個暗示。 – raichoo 2010-04-26 18:47:11