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

问题描述 投票:2回答:2

这是一个很好的例子:

  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

我收到以下错误:

错误:(53,11)找不到参数F的隐含值:cats.Functor [Some] res < - ReaderT((:Service)=> Some(10))错误:(53,11)方法参数不够map :(隐式F:cats.Functor [Some])cats.data.Kleisli [Some,com.savdev.Service,Int]。未指定的值参数F. res < - ReaderT((:Service)=> Some(10))

要修复第二个例子中的错误,我必须返回Some,但Option,它是Some的父级:

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

你能解释一下吗?为什么在第一个例子中返回Some,而不是Option,工作正常。为什么在第二个例子的同时,返回Some不编译?有没有Scala编译器编译案例的选项,就像在第二个例子中一样?或其他解决方案。

scala typeclass scala-cats for-comprehension subtyping
2个回答
4
投票
  1. 在第一种情况下,它直接在map上调用Some,已知它返回Option(普通多态与Some的子类Option),然后它继续找到Functor[Option]
  2. 在第二种情况下,函数的返回类型被推断为Some[Int],并且编译器尝试查找Functor[Some]类型类的实例,以便在Reader上调用方法(带有类型类Functor的ad-hoc多态),但是这失败了,因为没有Some的算子。

主要的问题是Some不仅仅是Option类型的实例的构造函数(例如,它将在Haskell中),但它实际上是(大多数无用的)类型Some实例的构造函数,它有时会混淆类型推理/暗示解决方案。

如果你想强制生成的类型是Option[Int],使用Option(10)来构造SomeOption.empty来构造None


3
投票

尝试

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。这有时可以改善类型推断。实际上它是Option,它是Functor的一个实例,而不是Some

查看https://blog.softwaremill.com/9-tips-about-using-cats-in-scala-you-might-want-to-know-e1bafd365f88中的“扩展方法构造函数”

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

© www.soinside.com 2019 - 2024. All rights reserved.