我已经开始使用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]]
答案 0 :(得分:2)
Applicative提供ap
和pure
,但不保证提供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