直接使用Scala类型类而没有隐式证据对象

Tom*_*Tom 1 types scala implicit typeclass

我想直接使用类型类的函数而不必引用隐式证据对象.

现在我已经以推荐的方式实现了类型类(至少我认为是这样):

object Main {
    import Implicits._
    import Implicits.monoidInt._

    def main(args: Array[String]): Unit = {
        println(addTwice(1,2))
    }
}

object Implicits {
    implicit object monoidInt extends Monoid[Int] {
        def zero: Int = 0
        def append(x: Int, y: Int): Int = x + y
    }
}

trait Monoid[A] {
    def zero: A
    def append(x: A, y: A): A
}
Run Code Online (Sandbox Code Playgroud)

而不是addTwice像:

def addTwice[A](x: A, y: A)(implicit ev: Monoid[A]): A = {
        ev.append(ev.append(x,y), y)
}
Run Code Online (Sandbox Code Playgroud)

我想写:

def addTwice[A: Monoid[A]](x: A, y: A): A = x.append(y).append(y)
Run Code Online (Sandbox Code Playgroud)

这可能吗?

Łuk*_*asz 6

对的,这是可能的.你需要这么称呼Ops.它允许向具有定义的类型类实例的类的对象添加方法.

您定义MonoidOps具有该值的特征和类型类的实例,然后在其方法中使用它们,因此基本上它封装了该ev变量的用法.

然后定义一个convertion,A用于MonoidOps[A]设置对象以及通过隐式参数获取的实例.

trait Monoid[A] {
    def zero: A
    def append(x: A, y: A): A
}

object Implicits {
    implicit object monoidInt extends Monoid[Int] {
        def zero: Int = 0
        def append(x: Int, y: Int): Int = x + y
    }

    trait MonoidOps[A] {
        def instance: Monoid[A]
        def self: A
        def |+|(y: A): A = instance.append(self, y)
    }

    implicit def toMonoidOps[A](target: A)(implicit M: Monoid[A]) = new MonoidOps[A] {
        val instance = M
        val self = target
    }
}

import Implicits._

def addTwice[A: Monoid](x: A, y: A): A = x |+| y |+| y

scala> println(addTwice(1,2))
5
Run Code Online (Sandbox Code Playgroud)

MonoidOps并且toMonoidOps可以用这样的隐式类替换:

implicit class MonoidOps[A](val self: A)(implicit M: Monoid[A]) {
    def |+|(y: A): A = M.append(self, y)
}
Run Code Online (Sandbox Code Playgroud)

看看可以为您生成样板的仿真项目.