在哪里放置implicits和辅助函数,traits与companion对象

时间:2018-06-11 06:56:38

标签: scala design-patterns implicit-conversion scalaz

我首先描述思考方式,然后是我的问题。我使用Functor定义作为示例。它是在scalaz中定义的,因此我将其用作一个小变化的例子,使其不那么复杂。

这是i模块定义,我放在Functor文件中:

Functor.scala

现在我想为精确类型定义模块的一些含义,例如trait Functor[F[_]] { def map[A,B](fa: F[A])(f: A => B): F[B] } 。另外,我想定义一个通用List函数,它隐式接受fmap。最好将它们定义为尽可能接近Functor特征。我认为Scala中最好的地方(考虑#1)是一个伴侣对象。以下是同一Functor文件中的定义:

Functor.scala

我可以在客户端代码中隐式使用object Functor { def fmap[F[_], A,B](as:F[A])(f:A=>B) (implicit ff:Functor[F]):F[B] = ff.map(as)(f) implicit val listFunctor = new Functor[List] { def map[A,B](as: List[A])(f: A => B): List[B] = as map f } } fmap,例如:

Functor

通常,当我们定义具有函数/函数集的模块时,我们还希望丰富现有类型,以便能够将我们的新函数用作这些现有类型的API的一部分。在Scala中,我们可以通过隐式转换实现它。这是一个import com.savdev.NewLibrary._ val r = fmap(List(1,2))(_.toString) 最终类,允许从某些泛型类型转换为FunctorOps

Functor

我将函数命名为final class FunctorOps[F[_], A](self: F[A])(implicit ff:Functor[F]){ def qmap[B](f:A=>B):F[B] = ff.map(self)(f) } fmap,以避免错误地使用针对不同类型存在的qmap函数。

现在我想要将隐式转换器定义为map。作为我想到的第一个选择 - 使用伴侣对象。但是看一下我发现的scalaz代码,他们主要使用它的特征:

FunctorOps

有特征我可以编写它们并用一个词导入。这是一个特征的例子,但我可以扩展它们中的很多:

trait ToFunctorOps {
  implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) =
    new FunctorOps[F,A](v)
}

现在在客户端代码中,我只能导入object NewLibrary extends ToFunctorOps ,这比导入每个随播广告对象要容易得多:

NewLibrary

比较选项,特征与伴侣对象,我发现使用特征是一种更灵活的方式。首先,因为我可以组成它们。也许我想念一些事情,我的结论是错误的。所以问题是:

  1. 使用伴随对象时,是否可以为我提供明确的用例,这是定义泛型函数和implicits(如果存在)的更有效方法。
  2. 有没有办法组成伴侣对象?他们是单身人士,但Scala是比我预期更强大的语言。可能有一些方法可以做到这一点。
  3. 是否有指南说明我应该选择哪个选项以及何时使用。

0 个答案:

没有答案