将运算符分配给Scala中的变量

时间:2014-10-01 14:40:40

标签: scala operators

鉴于Scala中有这么多代码:

val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = (d1, d2) => d1 ++ d2

可以缩短为:

val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = _ ++ _

实际上代码的作用是重命名Map [VertexId,Factor]的operator ++,因此:有没有办法将该运算符赋值给变量?就像在这个想象中的例子一样:

val mapMerge : (Map[VertexId, Factor], Map[VertexId, Factor]) => Map[VertexId, Factor] = Map.++

并且可能使用类型推断就可以编写

val mapMerge = Map[VertexId,Factor].++

由于

1 个答案:

答案 0 :(得分:6)

不幸的是,不,因为"运营商" Scala中的实例方法 - 不是来自类型类的函数,就像在Haskell中一样 在你编写_ ++ _时,你正在创建一个带有未命名参数的新的2参数函数(lambda)。这相当于(a, b) => a ++ b,相当于(a, b) => a.++(b),但不等同于(a, b) => SomeClass.++(a, b)

您可以使用隐式参数来模拟类型类(请参阅"typeclasses in scala" presentation

你可以通过"运营商"像函数 - 它们不是真正的运算符。你可以拥有看起来相同的运营商。见this example

object Main {

    trait Concat[A] { def ++ (x: A, y: A): A }
    implicit object IntConcat extends Concat[Int] {
        override def ++ (x: Int, y: Int): Int = (x.toString + y.toString).toInt
    }

    implicit class ConcatOperators[A: Concat](x: A) {
        def ++ (y: A) = implicitly[Concat[A]].++(x, y)
    }

    def main(args: Array[String]): Unit = {
        val a = 1234
        val b = 765

        val c = a ++ b // Instance method from ConcatOperators — can be used with infix notation like other built-in "operators"

        println(c)

        val d = highOrderTest(a, b)(IntConcat.++) // 2-argument method from the typeclass instance

        println(d)
        // both calls to println print "1234765"
    }

    def highOrderTest[A](x: A, y: A)(fun: (A, A) => A) = fun(x, y)

}

这里我们定义Concat类型类并为Int创建一个实现,我们在类型类中使用类似运算符的名称。

因为你可以为任何类型实现一个类型类,你可以使用任何类型的这种技巧 - 但这需要编写相当多的支持代码,有时它不值得结果。