简体   繁体   English

直接使用Scala类型类而无需隐式证据对象

[英]Use Scala typeclasses directly without implicit evidence object

I'd like to use the functions of a typeclass directly without having to refer to the implicit evidence object. 我想直接使用类型类的函数,而不必引用隐式证据对象。

Right now I have implemented a typeclass the recommended way (at least I think so): 现在,我已经以推荐的方式实现了类型类(至少我这样认为):

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
}

Instead of writing addTwice like: 而不是像这样编写addTwice

def addTwice[A](x: A, y: A)(implicit ev: Monoid[A]): A = {
        ev.append(ev.append(x,y), y)
}

I'd like to write: 我想写:

def addTwice[A: Monoid[A]](x: A, y: A): A = x.append(y).append(y)

Is this possible? 这可能吗?

Yes it is possible. 对的,这是可能的。 You need so called Ops . 您需要所谓的Ops It allows to add methods to objects of classes that have instance of the typeclass defined. 它允许向已定义typeclass实例的类的对象添加方法。

You define the MonoidOps trait that has that value and instance of typeclass and then uses those in its methods, so basically it encapsulates usage of that ev variable. 您定义具有该值和MonoidOps实例的MonoidOps特征,然后在其方法中使用它们,因此基本上它封装了该ev变量的用法。

Then define a convertion from A to MonoidOps[A] that sets the object as well as the instance that is taken through implicit parameter. 然后定义从AMonoidOps[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 and toMonoidOps could be replaced with implicit class like this: MonoidOpstoMonoidOps可以替换为隐式类,如下所示:

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

Take look at simulacrum project that can generate the boilerplate for you. 看一下可以为您生成样板的模拟项目。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM