2010-04-25 48 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