导入 FlatMap 实例会破坏 Applicative builder 语法
Importing FlatMap instance breaks Applicative builder syntax
对于我的示例,我将使用 Option
s,但在我的实际代码中,我使用的是自定义数据类型。添加导入 import cats.std.option._
将解决示例中的问题。我有一些看起来像这样的代码:
import cats.{FlatMap, Eval, Applicative}
import cats.data.Kleisli
import cats.syntax.all._
implicit val optionApplicative = new Applicative[Option] {
override def pure[A](x: A): Option[A] = Option(x)
override def ap[A, B](fa: Option[A])(f: Option[(A) => B]): Option[B] = for {
a <- fa
fUnwrapped <- f
} yield fUnwrapped(a)
}
val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
此代码正在编译,运行 没问题。
接下来我用 Kleisli
编写了一些 return Option
:
的函数
val test2 : List[Int] => Option[Int] = {
val f = (xs : List[Int]) => xs.headOption
val g = (x : Int) => Option(x)
Kleisli(f).andThen(g).run
}
代码没有编译,因为我的数据类型没有 FlatMap
实例。我创建了一个:
implicit val optionFlatmap = new FlatMap[Option] {
override def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
override def map[A, B](fa: Option[A])(f: (A) => B): Option[B] = fa.map(f)
}
导入 FlatMap
实例(或在同一文件中定义它)后,构建器语法不再编译。我收到错误:
error: value |@| is not a member of Option[Int]
[ERROR] val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
[ERROR] ^
为什么导入 FlatMap
实例会破坏构建器语法?我该如何解决这个问题?
使用 -Xlog-implicits
编译器标志对此进行调试很有帮助,它会告诉您编译器尝试了哪些隐式,以及它们失败的原因。在您的情况下,第一条消息(至少对我而言)对此进行了解释:
scala> (Option(4) |@| Option("name")).map((_, _))
<console>:20: applySyntax is not a valid implicit value for Option[Int] => ?{def |@|: ?} because:
ambiguous implicit values:
both value optionApplicative of type => cats.Applicative[Option]
and value optionFlatmap of type => cats.FlatMap[Option]
match expected type cats.Apply[Option]
(Option(4) |@| Option("name")).map((_, _))
要使应用操作起作用,需要隐式 Apply[Option]
,但 Applicative
和 FlatMap
都扩展 Apply
,因此编译器不知道是哪一个选择。对此的简单解决方案是将两个实例组合成 Monad
的实例,它扩展了 Applicative
和 FlatMap
.
import cats._
import cats.data.Kleisli
import cats.syntax.all._
implicit val optionMonad = new Monad[Option] {
def pure[A](x: A): Option[A] = Option(x)
def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
}
现在一切正常:
scala> val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
test: Option[(Int, String)] = Some((4,name))
scala> val test2 : List[Int] => Option[Int] = {
val f = (xs : List[Int]) => xs.headOption
val g = (x : Int) => Option(x)
Kleisli(f).andThen(g).run
}
test2: List[Int] => Option[Int] = <function1>
对于我的示例,我将使用 Option
s,但在我的实际代码中,我使用的是自定义数据类型。添加导入 import cats.std.option._
将解决示例中的问题。我有一些看起来像这样的代码:
import cats.{FlatMap, Eval, Applicative}
import cats.data.Kleisli
import cats.syntax.all._
implicit val optionApplicative = new Applicative[Option] {
override def pure[A](x: A): Option[A] = Option(x)
override def ap[A, B](fa: Option[A])(f: Option[(A) => B]): Option[B] = for {
a <- fa
fUnwrapped <- f
} yield fUnwrapped(a)
}
val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
此代码正在编译,运行 没问题。
接下来我用 Kleisli
编写了一些 return Option
:
val test2 : List[Int] => Option[Int] = {
val f = (xs : List[Int]) => xs.headOption
val g = (x : Int) => Option(x)
Kleisli(f).andThen(g).run
}
代码没有编译,因为我的数据类型没有 FlatMap
实例。我创建了一个:
implicit val optionFlatmap = new FlatMap[Option] {
override def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
override def map[A, B](fa: Option[A])(f: (A) => B): Option[B] = fa.map(f)
}
导入 FlatMap
实例(或在同一文件中定义它)后,构建器语法不再编译。我收到错误:
error: value |@| is not a member of Option[Int]
[ERROR] val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
[ERROR] ^
为什么导入 FlatMap
实例会破坏构建器语法?我该如何解决这个问题?
使用 -Xlog-implicits
编译器标志对此进行调试很有帮助,它会告诉您编译器尝试了哪些隐式,以及它们失败的原因。在您的情况下,第一条消息(至少对我而言)对此进行了解释:
scala> (Option(4) |@| Option("name")).map((_, _))
<console>:20: applySyntax is not a valid implicit value for Option[Int] => ?{def |@|: ?} because:
ambiguous implicit values:
both value optionApplicative of type => cats.Applicative[Option]
and value optionFlatmap of type => cats.FlatMap[Option]
match expected type cats.Apply[Option]
(Option(4) |@| Option("name")).map((_, _))
要使应用操作起作用,需要隐式 Apply[Option]
,但 Applicative
和 FlatMap
都扩展 Apply
,因此编译器不知道是哪一个选择。对此的简单解决方案是将两个实例组合成 Monad
的实例,它扩展了 Applicative
和 FlatMap
.
import cats._
import cats.data.Kleisli
import cats.syntax.all._
implicit val optionMonad = new Monad[Option] {
def pure[A](x: A): Option[A] = Option(x)
def flatMap[A, B](fa: Option[A])(f: (A) => Option[B]): Option[B] = fa.flatMap(f)
}
现在一切正常:
scala> val test : Option[(Int, String)] = (Option(4) |@| Option("name")).map((_, _))
test: Option[(Int, String)] = Some((4,name))
scala> val test2 : List[Int] => Option[Int] = {
val f = (xs : List[Int]) => xs.headOption
val g = (x : Int) => Option(x)
Kleisli(f).andThen(g).run
}
test2: List[Int] => Option[Int] = <function1>