如何flatMap猫

时间:2019-12-07 11:29:10

标签: scala functional-programming scala-cats applicative flatmap

我已经开始使用Cats学习函数式编程,并且坚持使用flatMapping(合并)应用程序F[List]

在纯Scala中非常简单的是将列表的列表映射成这样:

val animals = List("Dog", "Cat", "Bird")
def getBreads(animal: String): List[String] = ...

val allAnimalsBreads = animals.flatMap(animal => getBread(animal)) // this will be just List[String]

如果所有内容都用应用程序包装,该怎么办?

val animals = List("Dog", "Cat", "Bird").pure[F]
def getBreads(animal: String): F[List[String]] = ...

val allAnimalsBreads = ? // this should be F[List[String]]

2 个答案:

答案 0 :(得分:2)

Applicative提供appure,但不保证提供Monad提供的flatMap

  

Monad用新功能Applicative扩展了flatten类型的类。

如果F是单子,那么至少在scalaz中,我们可以使用ListT,例如

import scalaz._
import ListT._
import scalaz.std.option._

val animals: Option[List[String]] = Some(List("Dog", "Cat", "Bird"))
def getBreeds(animal: String): Option[List[String]] = ???

(for {
  animal <- listT(animals)
  breed <- listT(getBreeds(animal))
} yield breed).run

但是猫似乎不提供ListT

  

ListT的幼稚实现存在关联性问题; ...可以创建一个ListT   遇到这些问题,但效率往往很低。对于很多   用例中,Nested可用于实现所需的结果。


这里是您不应该使用的疯狂解决方案的尝试。考虑仅具有Validated实例的Applicative。让我们提供一个Monad实例,即使Validated is not a Monad

implicit def validatedMonad[E]: Monad[Validated[E, *]] =
  new Monad[Validated[E, *]] {
    def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
      fa match {
        case Valid(a) => f(a)
        case i @ Invalid(_) => i
      }

    def pure[A](x: A): Validated[E, A] = Valid(x)

    def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
  }

validatedMonad的实现取自scala-exercises.org/cats/validated

接下来,让我们通过shims互操作层使scalaz的listT在猫中可用

libraryDependencies += "com.codecommit" %% "shims" % "2.1.0"

将所有内容放在一起

import cats._
import cats.Monad
import cats.data.Validated.{Invalid, Valid}
import cats.data.{Nested, OptionT, Validated, ValidatedNec}
import cats.implicits._
import scalaz.ListT._
import shims._

implicit def validatedMonad[E]: Monad[Validated[E, *]] =
  new Monad[Validated[E, *]] {
    def flatMap[A, B](fa: Validated[E, A])(f: A => Validated[E, B]): Validated[E, B] =
      fa match {
        case Valid(a) => f(a)
        case i @ Invalid(_) => i
      }

    def pure[A](x: A): Validated[E, A] = Valid(x)

    def tailRecM[A, B](a: A)(f: A => Validated[E, Either[A, B]]) = ???
  }

val animals: Validated[String, List[String]] = List("Dog", "Cat", "Bird").valid
def getBreeds(animal: String): Validated[String, List[String]] = ???

(for {
  animal <- listT(animals)
  breed <- listT(getBreeds(animal))
} yield breed).run

请注意,此“解决方案”违反了一元法,不是很普遍,很可能引起混乱,因此请不要使用它。

答案 1 :(得分:1)

对于fabricjs_obj .on('mousedown', function (event) { event.target.dragStart = event.pointer }) fabricjs_obj .on('mouseup', function (event) { const a = event.target.dragStart const b = event.pointer const obj = event.target if (a.x != b.x || a.y != b.y) { console.log('obj dragged: '+obj) return // stop event handler } console.log('obj clicked: '+obj) // process click event }) ,这是不可能的。对于Applicative,如果您不想使用非常规转换器Monad,可以这样做

ListT