在scalaz中,当我们定义模块时,我们还定义了隐式的辅助函数。这是定义的示例以及客户端如何使用它:

trait Functor[F[_]] {
  def map[A,B](fa: F[A])(f: A => B): F[B]
}
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
  }
}
...
import com.savdev.NewLibrary._
val r = fmap(List(1,2))(_.toString)

final class FunctorOps[F[_], A](self: F[A])(implicit ff:Functor[F]){
  def qmap[B](f:A=>B):F[B] = ff.map(self)(f)
}
trait ToFunctorOps {
  implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) =
    new FunctorOps[F,A](v)
}
object NewLibrary extends ToFunctorOps
...
import com.savdev.NewLibrary._
val r2 = List(1, 4) qmap (x=>x.toString)

代码略有更改。但想法是我们定义:
  • 抽象及其API(代数)
  • 定义使用隐式和自身隐式的助手通用函数
  • 丰富现有类型,以便能够使用我们的新抽象。为此使用隐式转换。在scalaz中,我们为特征
  • 中的包装器和隐式转换器定义了最终类

    综上所述,它的动机以及客户可以使用它的方式很明显。但是在每个这样的模块定义的scalaz中,也有一个相关的*Syntax类。我不明白它的目的。您能否解释一下为什么需要它,以及如何在客户端代码中使用它。

    在Scalaz中,其定义为:
    trait FunctorSyntax[F[_]] {
      implicit def ToFunctorOps[A](v: F[A]): FunctorOps[F, A] =
        new FunctorOps[F, A](v)(FunctorSyntax.this.F)
      def F: Functor[F]
    }
    

    更新:

    伙计们,我似乎还不够清楚,或者对我们所有人来说,话题都比较复杂。

    我需要了解两个特征之间的区别:
    trait ToFunctorOps {
      implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) =
        new FunctorOps[F,A](v)
    }
    


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

    这两个特征都定义了创建FunctorOps的通用方法,它们都具有相同的可见性规则。
    第一个ToFunctorOps特性,它本身不是泛型的,它仅使用[F[_],A]定义了泛型方法。结果,我可以将很多这样的特征组合到一个对象中,然后一次将它们全部导入。我举了一个例子,客户如何使用这些特征:
    object NewLibrary extends ToFunctorOps
    ...
    import com.savdev.NewLibrary._
    val r2 = List(1, 4) qmap (x=>x.toString)
    

    这种特性已经给客户提供了隐式注入(inject)方法的可能性。为什么我们需要FunctorSyntax?此FunctorSyntax特性是[F[_]]上的通用名称。扩展它时,必须在定义中提供一个类型。因为现在在特质定义中使用了F[_],所以一个函数具有较少的通用参数,只有[A]

    我问你们,如果您能帮忙和不理解,请给我一个代码示例,客户端如何使用此FunctorSyntax特性。确实这还不清楚。

    现在,我看到尝试解释其他主题的信息,但是没有解释原始主题的信息:
  • 如何创建隐式类,而不是隐式函数。
  • 最终* Ops类和特征(包括可见性)之间的差异。在这里,我们比较具有相同可见性的2个特征。
  • 解释一般方法注入(inject),它们如何提供帮助。 ToFunctorOps已经提供了此功能。

  • 伙计们,请再次显示社区USE CASES via CODE of FunctorSyntax。代码本身始终是最好的文档。

    此致

    最佳答案

    从在scalaz代码库中看到的内容来看,我认为FunctorSyntax是启用语法的另一种方法。他们这样定义Functor(简化):

    trait Functor {
      def map[A, B](fa: F[A])(f: A => B): F[B]
    
      val functorSyntax = new FunctorSyntax[F] { def F = Functor.this }
    }
    

    这启用了以下工作方式:
    def foo[F[_]](f: F[String])(implicit F: Functor[F]): F[Int] = {
      import F.functorSyntax._
      f.map(_.length)
    }
    

    比较ToFunctorOps如何添加语法:
    package scalaz.syntax { // simplified version of the scalaz codebase
      object functor extends ToFunctorOps
    }
    
    import scalaz.syntax.functor._
    def foo[F[_]: Functor](f: F[String]): F[Int] = f.map(_.length)
    

    关于Scalaz,*语法类的目的,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50792102/

    10-12 20:30