简体   繁体   English

Scalaz,*语法类的目的

[英]Scalaz, the purpose of *syntax classes

In scalaz when we define a module, we additionally define implicit, helper functions. 在我们定义模块的scalaz中,我们另外定义了隐式的辅助函数。 Here is an example of definition and how it could be used by a client: 以下是定义的示例以及客户端如何使用它:

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)

The code is slightly changed. 代码稍有改动。 But the idea is that we define: 但我们的想法是我们定义:

  1. An abstraction and its API (algebra) 抽象及其API(代数)
  2. Define helper generic functions that use implicits and implicits themselves 定义使用implicits并隐含自身的辅助通用函数
  3. Enrich existing types to be able to use our new abstraction. 丰富现有类型以便能够使用我们的新抽象。 Implicit convertion is used for that. 隐式转换用于此。 In scalaz we define a final class for a wrapper and implicit converters in traits 在scalaz中,我们为特征中的包装器和隐式转换器定义最终类

All above, the motivation of it and how it can be used by a client is clear. 以上所述,它的动机以及客户如何使用它是显而易见的。 But in scalaz to each such module definition, there is also a related *Syntax class. 但是在每个这样的模块定义的scalaz中,还有一个相关的*Syntax类。 I cannot understand the purpose of it. 我无法理解它的目的。 Can you please exlain, why it is needed and HOW it can be used in a client code. 请问exlain,为什么需要它以及如何在客户端代码中使用它。

In Scalaz it is defined as: 在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]
}

UPDATED: 更新:

Guys, it seems I am not clear enough, or a topic is more complicated for all of us. 伙计们,似乎我不够清楚,或者对我们所有人来说,话题都更复杂。

What I need is to understand the difference between two traits: 我需要的是理解两个特征之间的区别:

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

vs.

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]
}

Both traits define a generic method that creates FunctorOps , both have the same visibility rules. 两个特征都定义了创建FunctorOps的通用方法,两者都具有相同的可见性规则。 The first ToFunctorOps trait, it is not generic itself, it defines only generic method with [F[_],A] . 第一个ToFunctorOps特性,它本身不是通用的,它只用[F[_],A]定义泛型方法。 As a result, I can compose a lot of such traits into one object and import all of them at once. 结果,我可以将很多这样的特征组合成一个对象并一次导入所有这些特征。 I gave an example how such traits could be used by a client: 我举了一个例子,说明客户可以使用这些特征:

object NewLibrary extends ToFunctorOps
...
import com.savdev.NewLibrary._
val r2 = List(1, 4) qmap (x=>x.toString)

This trait already gives clients a possibility to inject methods implicitly. 这种特性已经为客户提供了隐式注入方法的可能性。 Why do we need FunctorSyntax ? 为什么我们需要FunctorSyntax This FunctorSyntax trait is a generic itself on [F[_]] . 这个FunctorSyntax特征在[F[_]]上是一个通用的。 When I extend it, I must provide a type in the definition. 当我扩展它时,我必须在定义中提供一个类型。 Because F[_] now is used in trait definition, a function has less generic parameters, only [A] . 因为F[_]现在用于特征定义,所以函数具有较少的泛型参数,仅[A]

I am asking you guys, if you can help and undestand, give me a code example how this FunctorSyntax trait can be used by a client. 我问你们,如果你们可以提供帮助和解决,请给我一个代码示例,说明客户端如何使用FunctorSyntax特性。 Exactly this is not clear. 究竟这还不清楚。

Right now I see tries to explain the other topics, but not the original: 现在我看到尝试解释其他主题,但不是原来的:

  1. How to create implicit classes, instead of implicit functions. 如何创建隐式类,而不是隐式函数。
  2. Difference between final *Ops class and a trait, including their visibility. 最终* Ops类与特征之间的差异,包括其可见性。 Here we compare 2 traits with the same visibility. 在这里,我们比较具有相同可见性的2个特征。
  3. Explaining in general method injection, how they help. 解释一般方法注射,它们如何帮助。 This functionality is provided already with ToFunctorOps . ToFunctorOps已提供此功能。

Guys, again, please show the community USE CASES via CODE of FunctorSyntax . 伙计们,请再次USE CASES via CODE of FunctorSyntax向社区展示USE CASES via CODE of FunctorSyntax Code itself is always the best documentation. 代码本身始终是最好的文档。

Best regards 最好的祝福

From what I can see in the scalaz codebase, I think that FunctorSyntax is meant as an alternative way of enabling syntax. 从我在scalaz代码库中可以看到,我认为FunctorSyntax是一种启用语法的替代方法。 They define Functor like this (simplified): 他们像这样定义Functor (简化):

trait Functor {
  def map[A, B](fa: F[A])(f: A => B): F[B]

  val functorSyntax = new FunctorSyntax[F] { def F = Functor.this }
}

This enables the following way of working: 这样可以实现以下工作方式:

def foo[F[_]](f: F[String])(implicit F: Functor[F]): F[Int] = {
  import F.functorSyntax._
  f.map(_.length)
}

Compare to how ToFunctorOps adds syntax: 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)

Here's a use case where you would use functorSyntax: 这是一个使用functorSyntax的用例:

import org.scalatest.{FreeSpec, Matchers}

import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{Await, Future}
import scala.concurrent.duration._
import scalaz._
import Scalaz._

import scala.language.postfixOps

class ScalazTest extends FreeSpec with Matchers {
  "compose functors" in {
    val composedFunctor = Functor[Future] compose Functor[List] compose Functor[Option]
    import composedFunctor.functorSyntax._

    val actual = Future.successful(List(Some(1), Some(2), None, Some(4))) fmap (x => x * 2)
    Await.result(actual, 10 seconds) shouldBe List(Some(2), Some(4), None, Some(8))
  }
}

The idea is that you can compose several functor instaces and import the final composed functor's instance in scope and work with it. 这个想法是你可以组合几个函子实例并在范围内导入最终组成的仿函数实例并使用它。 Notice that fmap is resolved to composedFunctor.functorSyntax in this case and it works on 3 levels of nesting ( Future[List[Option[Integer]]] ) while still accepting a function that deals with primitive types. 请注意, fmap决心composedFunctor.functorSyntax在这种情况下,它的工作原理筑巢在3层( Future[List[Option[Integer]]]同时还接受与原始类型的交易功能。

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

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