隐式参数的顺序在Scala中是否重要?

时间:2015-03-19 08:44:50

标签: scala implicit

给出一些方法

def f[A,B](p: A)(implicit a: X[A,B], b: Y[B])

隐式参数列表中a之前的b顺序对类型推断是否重要?

我认为只有参数在不同参数列表中的位置很重要,例如类型信息仅从左到右通过参数列表流动。

我问,因为我注意到在单隐式列表中更改隐式参数的顺序使我的程序编译。

真实示例

以下代码正在使用:

  • shapeless 2.1.0
  • Scala 2.11.5

这是一个简单的sbt构建文件,可以帮助编译示例:

scalaVersion := "2.11.5"

libraryDependencies += "com.chuusai" %% "shapeless" % "2.1.0"

scalaSource in Compile := baseDirectory.value

在示例上。此代码编译:

import shapeless._
import shapeless.ops.hlist.Comapped

class Foo {
  trait NN
  trait Node[X] extends NN
  object Computation {
    def foo[LN <: HList, N <: HList, TupN <: Product, FunDT]
    (dependencies: TupN)
    (computation: FunDT)
    (implicit tupToHlist: Generic.Aux[TupN, LN], unwrap: Comapped.Aux[LN, Node, N]) = ???
//    (implicit unwrap: Comapped.Aux[LN, Node, N], tupToHlist: Generic.Aux[TupN, LN]) = ???

    val ni: Node[Int] = ???
    val ns: Node[String] = ???
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
  }
}

并且此代码失败

import shapeless._
import shapeless.ops.hlist.Comapped

class Foo {
  trait NN
  trait Node[X] extends NN
  object Computation {
    def foo[LN <: HList, N <: HList, TupN <: Product, FunDT]
    (dependencies: TupN)
    (computation: FunDT)
//    (implicit tupToHlist: Generic.Aux[TupN, LN], unwrap: Comapped.Aux[LN, Node, N]) = ???
    (implicit unwrap: Comapped.Aux[LN, Node, N], tupToHlist: Generic.Aux[TupN, LN]) = ???

    val ni: Node[Int] = ???
    val ns: Node[String] = ???
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
  }
}

出现以下编译错误

Error:(22, 25) ambiguous implicit values:
 both method hnilComapped in object Comapped of type [F[_]]=> shapeless.ops.hlist.Comapped.Aux[shapeless.HNil,F,shapeless.HNil]
 and method hlistComapped in object Comapped of type [H, T <: shapeless.HList, F[_]](implicit mt: shapeless.ops.hlist.Comapped[T,F])shapeless.ops.hlist.Comapped.Aux[shapeless.::[F[H],T],F,shapeless.::[H,mt.Out]]
 match expected type shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N]
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^
Error:(22, 25) could not find implicit value for parameter unwrap: shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N]
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^
Error:(22, 25) not enough arguments for method foo: (implicit unwrap: shapeless.ops.hlist.Comapped.Aux[LN,Foo.this.Node,N], implicit tupToHlist: shapeless.Generic.Aux[(Foo.this.Node[Int], Foo.this.Node[String]),LN])Nothing.
Unspecified value parameters unwrap, tupToHlist.
    val x = foo((ni,ns))((i: Int, s: String) => s + i.toString)
                        ^

3 个答案:

答案 0 :(得分:2)

  1. 通常没关系。如果您查看language spec,则不会提及依赖于参数顺序的分辨率。

  2. 我查看了无形的源代码,我无法想出为什么会出现这种错误。

  3. 快速搜索语言的错误回购,我发现similar issue显然已经解决了。但它没有说明修复是否涉及处理症状(使上下文边界不破坏编译)或原因(对隐式参数排序的限制。)

  4. 因此,我认为这是一个编译器错误,它与第3点中链接的问题紧密相关。

    此外,如果您能找到比我自己更严格的分析产生的第二意见,我建议您提交错误报告:)

    希望这会让你的思绪得到安息。干杯!

答案 1 :(得分:1)

根据我对Lorand Szakacs提到的the issue的评论的解读,我得出的结论是隐式参数的顺序在Scala编译器的当前版本2.11中很重要。

这是因为参与讨论的开发人员似乎认为订单很重要;他们没有明确说明。

我不知道有关此主题的语言规范。

答案 2 :(得分:0)

重新排序它们只会破坏显式传递它们的代码,以及所有已编译的代码。其他一切都不会受到影响。