scala 无法解析Monad约束类型上的符号flatMap

yi0zb3m4  于 2023-06-23  发布在  Scala
关注(0)|答案(1)|浏览(141)

我一直在玩scala cats,最后被隐式和类型限制所困。
假设以下定义:

trait Client[F[_]] {

  def fetchPossiblePairs(fetcher: Uri => F[List[String]]): F[List[Rate.Pair]]

  def fetchQuotes(currencyPairs: List[Rate.Pair], fetcher: Uri => F[List[QuoteDTO]]): F[List[Rate]]

  def convertRate(uri: Uri): F[List[QuoteDTO]]

  def symbols(uri: Uri): F[List[String]]

}

object Quotes {
  private def getCurrencyPairs[F[_]: Monad](client: Client[F],
                                            existingRates: Map[Rate.Pair, Rate]): F[List[Rate.Pair]] =
    if (existingRates.isEmpty) {
      client.fetchPossiblePairs(client.symbols)
    } else {
      existingRates.keySet.toList.pure[F]
    }

    private def updateCache(existingRates: Map[Rate.Pair, Rate], newRates: List[Rate]): Map[Rate.Pair, Rate] =
      newRates.foldRight(existingRates)((rate: Rate, acc: Map[Rate.Pair, Rate]) => acc.updated(rate.pair, rate))
}

下面的实现可以工作,但看起来很丑,而且不符合标准:

object Quotes {
  private def refreshRatesCache[F[_]: Monad](client: Client[F],
                                             existingRates: Map[Rate.Pair, Rate]): F[Map[Rate.Pair, Rate]] = {
    val currencyPairs1 = getCurrencyPairs(client, existingRates)

    Monad[F]
      .flatMap(currencyPairs1)(currencyPairs => client.fetchQuotes(currencyPairs, uri => client.convertRate(uri)))
      .map(quotes => updateCache(existingRates, quotes))
  }
}

使用for理解,IDE会显示错误Cannot resolve symbol flatMap

object Quotes {
  private def refreshRatesCache[F[_]: Monad](client: Client[F],
                                             existingRates: Map[Rate.Pair, Rate]): F[Map[Rate.Pair, Rate]] =
    for {
      currencyPairs <- getCurrencyPairs(client, existingRates)
      //            ^
      //            |--- Cannot resolve symbol flatMap
      //
      rates <- client.fetchQuotes(currencyPairs, uri => client.convertRate(uri))
    } yield updateCache(existingRates, rates)
}

SBT显示了一个稍微不同的错误:

value flatMap is not a member of type parameter F[List[Rate.Pair]]

我的理解是,这两个实现是相同的,只是使用了不同的语法糖。
getCurrencyPairs[F[_]: Monad](...)返回一个 Package 的ListF[List[Rate.Pair]],并且给定F[_]: Monad上的类型约束,我假设Scala应该能够推断出F extends Monad并找到Monad的所有方法(包括flatMap)。
整个for解析都在F[_]的相同上下文中工作,因此似乎不是类型不匹配。
我试图扩展隐式和for的理解,因此得到了这个丑陋的实现:

Monad[F]
      .flatMap
        (getCurrencyPairs(client, existingRates))
        (currencyPairs => client.fetchQuotes(currencyPairs, uri => client.convertRate(uri)))
      .map(quotes => updateCache(existingRates, quotes))

在我看来,使用(implicit m: Monad[F[_]])没有太大意义(至少我无法给出它的正确用法)。
我对Scala隐式并不是很精通,但我的代码似乎有些问题。我哪里错了?
我使用的版本是:

  • Scala 2.13.5
  • SBT 1.9.0
  • cats-core 2.5.0
  • cats-effects 2.4.1
n6lpvg4x

n6lpvg4x1#

这几乎肯定是由于缺少提供方法的导入。
添加import cats.syntax.all._

相关问题