Scala查看应用程序益智游戏

时间:2012-11-22 14:48:47

标签: scala types implicits

假设我们有以下两个特征:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

从第二个到第一个的隐式转换:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

我们创建一个Bar和一个整数列表:

val bar = new Bar {}
val stuff = List(1, 2, 3)

现在我希望以下内容有效:

bar howMany stuff

但事实并非如此:

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff
                          ^

所以我们转到the spec,这就是这样说的(粗体强调是我的):

  

视图适用于三种情况。

     
      
  1. [此处不相关。]

  2.   
  3. 在选择 em e T 如果选择器 m 不表示 T 的成员。在这种情况下,搜索视图 v   适用于 e ,其结果包含名为 m 的成员。该   搜索继续进行,如隐式参数的情况,其中   隐式范围是 T 之一。如果发现这样的观点,那么   选择 e.m 转换为 v(e).m

  4.   
  5. 在选择 em(args) e 类型为 T 时,如果选择器 m 表示 T 的某些成员,但这些成员都不适用于参数 args 。在这种情况下,搜索视图 v   适用于 e 且其结果包含方法 m   适用于 args 。搜索按照的情况进行   隐式参数,其中隐式范围是 T 之一。如果   找到这样的视图,选择 e.m 转换为    V(E).M(参数)

  6.   

所以我们尝试以下方法,认为工作一定太荒谬了:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar { def howMany = throw new Exception("I don't do anything!") }

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

但确实如此(至少在2.9.2和2.10.0-RC2上):

scala> bar howMany stuff
res0: Int = 3

这导致了一些非常奇怪的行为,例如在this workaround this problem中。

我有三个(密切相关的)问题:

  1. 是否有一种直截了当的方式(即,不涉及添加具有适当名称的假方法)以使视图在上述原始案例中正确应用?
  2. 有人可以提供解释此行为的规范吗?
  3. 假设这是预期的行为,它是否有意义呢?
  4. 我也很欣赏以前关于这个问题的讨论的任何链接 - 我对Google没有太多好运。

5 个答案:

答案 0 :(得分:1)

这似乎是一个错误所以我的答案是:

  1. 搜索针对Scala编译器报告的simliar错误,如果找不到,则报告新错误https://issues.scala-lang.org/
  2. 在这种情况下,那部分规范似乎并不重要,因为它没有谈论类型推断
  3. 对我没有任何意义
  4. PS。在2.8.1中,将虚拟方法添加到Bar的解决方法不会使其编译。

答案 1 :(得分:1)

供大家参考,这可能只是一个错误。您知道的方式是错误消息:

<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]

List [A]不是真正的类型 - 它是应用于其自己的类型参数的List。这不是一种可以要求的类型,因为它不是一种可以表达的类型。

[编辑 - 现在还为时过早,谁知道我在说什么。忽略上述内容,但您仍然可以点击链接。]

此相关票证为https://issues.scala-lang.org/browse/SI-6472

答案 2 :(得分:0)

用这个替换你的Foo:

trait Foo[_] { def howMany(xs: List[_]) = xs.size }

它有效,这对我来说更有意义,因为你绝对不会对A感兴趣。

答案 3 :(得分:0)

你的隐式转换似乎完全按照你的要求去做。

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

将Bar转换为新的Foo[A]对象。所以反过来

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff

它寻找一个&#39; A&#39;类型。

为了让你的工作按照你想要的方式(我认为),而不是在特征上定义视图,你可以在函数上完成它。

trait Foo { def howMany[A](xs: List[A]) = xs.size }
trait Bar
implicit def bar2foo[A](bar: Bar) = new Foo{}
val bar = new Bar {}
val stuff = List(1, 2, 3)

然后它应该给你你想要的结果。

scala> bar howMany stuff
res0: Int = 3

或者您可以在隐式函数

上定义视图
trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

implicit def bar2foo[A](bar: Bar) = new Foo[Int] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

我个人认为在功能上定义它更清晰。

答案 4 :(得分:0)

这虽然丑陋但似乎有效:

(bar: Foo[Int]) howMany stuff