在没有隐式证据对象的情况下直接使用 Scala 类型类
Use Scala typeclasses directly without implicit evidence object
我想直接使用类型类的函数,而不必引用隐式证据对象。
现在我已经按照推荐的方式实现了一个类型类(至少我是这么认为的):
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
}
而不是像这样写 addTwice
:
def addTwice[A](x: A, y: A)(implicit ev: Monoid[A]): A = {
ev.append(ev.append(x,y), y)
}
我想写:
def addTwice[A: Monoid[A]](x: A, y: A): A = x.append(y).append(y)
这可能吗?
是的,这是可能的。你需要所谓的Ops
。它允许向 classes 的对象添加方法,这些对象具有定义的类型 class 的实例。
您定义具有该值的 MonoidOps
特征和类型 class 的实例,然后在其方法中使用它们,因此基本上它封装了 ev
变量的用法。
然后定义一个从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
MonoidOps
和 toMonoidOps
可以替换为隐式 class,如下所示:
implicit class MonoidOps[A](val self: A)(implicit M: Monoid[A]) {
def |+|(y: A): A = M.append(self, y)
}
查看可以为您生成样板的 simulacrum 项目。
我想直接使用类型类的函数,而不必引用隐式证据对象。
现在我已经按照推荐的方式实现了一个类型类(至少我是这么认为的):
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
}
而不是像这样写 addTwice
:
def addTwice[A](x: A, y: A)(implicit ev: Monoid[A]): A = {
ev.append(ev.append(x,y), y)
}
我想写:
def addTwice[A: Monoid[A]](x: A, y: A): A = x.append(y).append(y)
这可能吗?
是的,这是可能的。你需要所谓的Ops
。它允许向 classes 的对象添加方法,这些对象具有定义的类型 class 的实例。
您定义具有该值的 MonoidOps
特征和类型 class 的实例,然后在其方法中使用它们,因此基本上它封装了 ev
变量的用法。
然后定义一个从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
MonoidOps
和 toMonoidOps
可以替换为隐式 class,如下所示:
implicit class MonoidOps[A](val self: A)(implicit M: Monoid[A]) {
def |+|(y: A): A = M.append(self, y)
}
查看可以为您生成样板的 simulacrum 项目。