Scala for-comprehension with Option 和 Some,由 ReaderT 包装

Scala for-comprehension with Option and Some, wrapped by ReaderT

这是一个运行良好的示例:

  import cats.data.ReaderT
  import cats.instances.option._
  ...
  def f1:ReaderT[Option, Service, Int] =
    ReaderT(service => for {
      res <- Some(10)
    } yield res )

这里是一个没有编译的例子:

  def f2:ReaderT[Option, Service, Int] =
    for {
      res <- ReaderT((_:Service) => Some(10))
    } yield res

我收到以下错误:

Error:(53, 11) could not find implicit value for parameter F: cats.Functor[Some] res <- ReaderT((:Service) => Some(10)) Error:(53, 11) not enough arguments for method map: (implicit F: cats.Functor[Some])cats.data.Kleisli[Some,com.savdev.Service,Int]. Unspecified value parameter F. res <- ReaderT((:Service) => Some(10))

要修复第二个示例中的错误,我必须 return 而不是 Some,而是 Option,它是 Some:[=20= 的父级]

  def f2:ReaderT[Option, Service, Int] =
    for {
      res <- ReaderT((_:Service) => Option(10))
    } yield res

你能解释一下吗?为什么在第一个例子中 returning Some,而不是 Option,工作正常。为什么在第二个例子中,returning Some 没有被编译? Scala 编译器是否有编译案例的选项,如第二个示例?或其他解决方案。

尝试

import cats.syntax.option._

def f2: ReaderT[Option, Service, Int] =
  for {
    res <- ReaderT((_: Service) => 10.some)
  } yield res

最好使用x.somenone(或none[X])而不是Some(x)None。它们的类型为 Option[X] 而不是 Some[X]None.type。这有时可以改进类型推断。实际上 OptionFunctor 的一个实例,而不是 Some.

https://blog.softwaremill.com/9-tips-about-using-cats-in-scala-you-might-want-to-know-e1bafd365f88

中查看"Extension method constructors"

在第一种情况下,您很幸运能够正确推断出类型。

  1. 在第一种情况下,它直接在 Some 上调用 map,这是 return 和 Option 已知的(带有子类的普通多态性Some of Option), 然后继续寻找 Functor[Option].

  2. 在第二种情况下,你的函数的return类型被推断为Some[Int],编译器试图找到一个Functor[Some]类型类的实例为了调用 Reader 上的方法(类型类 Functor 的临时多态性),但这失败了,因为 Some.

    [=40 没有函子=]

主要问题是 Some 不仅仅是 Option 类型实例的构造函数(例如 Haskell),但它实际上是类型 Some(大部分无用)实例的构造函数,有时会搞乱类型推断/隐式解析。

如果要强制结果类型为 Option[Int],请使用 Option(10) 构造 SomeOption.empty 构造 None