其他结果在哪里

时间:2017-05-05 09:15:55

标签: scala

我有以下适用的定义和实施:

import simulacrum._

@typeclass trait Applicative[F[_]] {

  def pure[A](a: A): F[A]

  def apply[A, B](fa: F[A])(ff: F[A => B]): F[B]

  def map[A,B](fa: F[A])(f: A => B): F[B] =
    apply(fa)(pure(f))

}

object Applicative {

  implicit val optionApplicative: Applicative[Option] = new Applicative[Option] {
    def pure[A](a: A): Option[A] = Some(a)

    def apply[A, B](fa: Option[A])(ff: Option[A => B]): Option[B] = (fa, ff) match {
      case (None, _) => None
      case (Some(_), None) => None
      case (Some(a), Some(f)) => Some(f(a))
    }

  }

  implicit val listApplicative: Applicative[List] = new Applicative[List] {
    def pure[A](a: A): List[A] = List(a)

    def apply[A, B](fa: List[A])(ff: List[A => B]): List[B] =
      (fa zip ff).map { case (a, f) => f(a) }

  }

}

当我在列表上执行地图时:

Applicative[List].map(List(1,2,3))(_ + 1)

我有:

res2: List[Int] = List(2)

但我确实期待List(2,3,4)。我做错了什么?

2 个答案:

答案 0 :(得分:4)

def apply[A, B](fa: List[A])(ff: List[A => B]): List[B] =
  (fa zip ff).map { case (a, f) => f(a) }

这是由ff尺寸 1 def pure[A](a: A): List[A] = List(a)引起的。

所以:

(fa zip ff).map { case (a, f) => f(a) }

=>:

List(1, 2, 3) zip List(f).map { case (a, f) => f(a) }

=>:

List((1, f)).map { case (a, f) => f(a) }

答案 1 :(得分:0)

要为@ chengpohi的答案添加解决方案,我想指出为Applicative提供List个实例的两种经典方式。

第一个是Zip,你已经实现了,所以当你有一个值列表和一个函数列表时,它会逐个应用元素函数(第一个函数应用于第一个元素) , 等等)。从两个大小为nm的列表开始,输出将是一个大小为min(n, m)的列表。

第二个是Cartesian,对于元素列表和函数列表,它将每个函数应用于每个元素。因此,如果您从大小为nm的列表开始,您将获得一个大小为n × m的列表。

以下是它的简单实现:

implicit val cartesian: Applicative[List] = new Applicative[List] {
  def pure[A](a: A): List[A] = List(a)

  def apply[A, B](fa: List[A])(ff: List[A => B]): List[B] = for {
    a <- fa
    f <- ff
  } yield f(a)
}

第二个更标准(它确实是从Monad实例继承的那个)并且是cat和scalaz AFAIK中的默认值。

您必须要问自己的是,在两个名单(大小超过1)上使用您的应用程序时,您有什么期望,以获得更好的想法。你在问题中说的话让我觉得你最好还是选择第二个。请记住,这两个是经典,但不是唯一可能的。如果您需要自定义实例,您可以定义它(请记住它应该遵守Applicative法律。)