如果没有烦人的虚拟参数来标记类型,Scala 隐式歧义就无法解决。
Scala implicit ambiguity doesn't get resolved without annoying dummy argument to mark the type.
在学习了 this 教程中的一些 Scala 高级类型示例之后,我开始尝试使用
(a) 隐式和 (b) 编写方法的技术,这些方法一般处理特征的子类
被定义为更高种类的类型。我已经在 (b) 上得到了很好的答案,这让我离解决以下问题更近了一步:
我想创建一个工厂来创建包装的单例容器(集合、列表、数组)
我传递给工厂函数的项目。 [ 即使已经有一个 Scala
做这个的库,我正在做这个作为一个学习练习。但是,嘿...如果有,请告诉我!]
最终结果应该让我这样做:
scala> var j: Set[String] = wrapItemInContainer("foo")
j: Set[String] = Set(foo)
scala> var k: List[Int] = wrapItemInContainer(9)
k: List[Int] = List(9)
我想到的解决方案如下所示。我必须提供一个烦人的虚拟最终参数,这样我才能
帮助编译器弄清楚我想要什么样的容器。这行得通,但令我感到困惑的是
我想将结果分配给 (j, k..etc.) 的变量的类型签名没有给出
编译器有足够的信息来确定需要使用哪个隐式定义的 ContainerFactory。
这个笨拙的解决方案有效:
trait ContainerFactory[M[_]] { def put[A](x: A): M[A] }
implicit val factory = new ContainerFactory[List] { def put[A](x: A) = List(x) } // factory for List containers
implicit val factory2 = new ContainerFactory[Set] { def put[A](x: A) = Set(x)} // factory for Set containers
def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A, helper: M[A]) : M[A] = {
val c = implicitly[ContainerFactory[M]]
c.put(item)
}
var j: List[Int] = wrapItemInContainer(9, List(0))
但我真的想要一些没有嘈杂的第二个参数的东西:
def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A) : M[A] = {
val c = implicitly[ContainerFactory[M[A]]]
c.put(item)
}
var j: List[Int] = wrapItemInContainer(9) // this does not work.
我收到此错误:
<console>:17: error: ambiguous implicit values:
both value factory of type => ContainerFactory[List]
and value factory2 of type => ContainerFactory[Set]
match expected type ContainerFactory[M]
var j: List[Int] = wrapItemInContainer(9)
非常感谢任何想法或提示!
-克里斯
您需要使 M 中的工厂协变。参见 https://groups.google.com/forum/#!topic/scala-language/dQEomVCH3CI and https://issues.scala-lang.org/browse/SI-7332。
这样编译:
import language.higherKinds
trait Factory[+M[_], A] { def put(x: A): M[A] }
implicit def factory1[A] =
new Factory[List, A] { def put(x: A) = List(x) }
implicit def factory2[A] =
new Factory[Set, A] { def put(x: A) = Set(x) }
def wrap[M[_], A](a: A)(
implicit factory: Factory[M, A]): M[A] =
factory.put(a)
val j: Set[String] = wrap("foo")
val k: List[Int] = wrap(9)
我冒昧地缩短了你的名字。我还按照您在 收到的建议将 A 设为工厂本身的类型参数。
在学习了 this 教程中的一些 Scala 高级类型示例之后,我开始尝试使用
(a) 隐式和 (b) 编写方法的技术,这些方法一般处理特征的子类
被定义为更高种类的类型。我已经在 (b)
我想创建一个工厂来创建包装的单例容器(集合、列表、数组) 我传递给工厂函数的项目。 [ 即使已经有一个 Scala 做这个的库,我正在做这个作为一个学习练习。但是,嘿...如果有,请告诉我!]
最终结果应该让我这样做:
scala> var j: Set[String] = wrapItemInContainer("foo")
j: Set[String] = Set(foo)
scala> var k: List[Int] = wrapItemInContainer(9)
k: List[Int] = List(9)
我想到的解决方案如下所示。我必须提供一个烦人的虚拟最终参数,这样我才能 帮助编译器弄清楚我想要什么样的容器。这行得通,但令我感到困惑的是 我想将结果分配给 (j, k..etc.) 的变量的类型签名没有给出 编译器有足够的信息来确定需要使用哪个隐式定义的 ContainerFactory。
这个笨拙的解决方案有效:
trait ContainerFactory[M[_]] { def put[A](x: A): M[A] }
implicit val factory = new ContainerFactory[List] { def put[A](x: A) = List(x) } // factory for List containers
implicit val factory2 = new ContainerFactory[Set] { def put[A](x: A) = Set(x)} // factory for Set containers
def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A, helper: M[A]) : M[A] = {
val c = implicitly[ContainerFactory[M]]
c.put(item)
}
var j: List[Int] = wrapItemInContainer(9, List(0))
但我真的想要一些没有嘈杂的第二个参数的东西:
def wrapItemInContainer[ M[A]: ContainerFactory, A](item: A) : M[A] = {
val c = implicitly[ContainerFactory[M[A]]]
c.put(item)
}
var j: List[Int] = wrapItemInContainer(9) // this does not work.
我收到此错误:
<console>:17: error: ambiguous implicit values:
both value factory of type => ContainerFactory[List]
and value factory2 of type => ContainerFactory[Set]
match expected type ContainerFactory[M]
var j: List[Int] = wrapItemInContainer(9)
非常感谢任何想法或提示!
-克里斯
您需要使 M 中的工厂协变。参见 https://groups.google.com/forum/#!topic/scala-language/dQEomVCH3CI and https://issues.scala-lang.org/browse/SI-7332。
这样编译:
import language.higherKinds
trait Factory[+M[_], A] { def put(x: A): M[A] }
implicit def factory1[A] =
new Factory[List, A] { def put(x: A) = List(x) }
implicit def factory2[A] =
new Factory[Set, A] { def put(x: A) = Set(x) }
def wrap[M[_], A](a: A)(
implicit factory: Factory[M, A]): M[A] =
factory.put(a)
val j: Set[String] = wrap("foo")
val k: List[Int] = wrap(9)
我冒昧地缩短了你的名字。我还按照您在