Scalaz,*语法类的目的



在 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)

代码略有变化。但这个想法是我们定义:

  1. 抽象及其API(代数(
  2. 定义使用隐式和隐式本身的帮助程序泛型函数
  3. 丰富现有类型,以便能够使用我们的新抽象。隐式转换用于此目的。在 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)

此特征已经使客户端可以隐式注入方法。为什么我们需要FunctorSyntax?这个 FunctorSyntax 特性本身就是[F[_]]上的泛型。当我扩展它时,我必须在定义中提供一个类型。由于F[_]现在用于特征定义,因此函数的泛型参数较少,只有[A]

我问你们,如果你们能提供帮助和取消立场,给我一个代码示例,客户如何使用这个FunctorSyntax特征。具体来说,这并不清楚。

现在我看到试图解释其他主题,但不是原始主题:

  1. 如何创建隐式类,而不是隐式函数。
  2. 最终 *Ops 类与特征之间的区别,包括它们的可见性。在这里,我们比较了具有相同可见性的 2 个特征。
  3. 解释一般方法进样,它们如何帮助。此功能已随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)

下面是一个使用 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))
}
}

这个想法是,您可以组合多个函子集合,并在作用域中导入最终组合函子的实例并使用它。请注意,在这种情况下,fmap被解析为composedFunctor.functorSyntax,它适用于 3 个级别的嵌套 (Future[List[Option[Integer]]](,同时仍然接受处理基元类型的函数。

最新更新