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

huangapple go评论46阅读模式
英文:

Cannot resolve symbol flatMap on Monad constrainted type

问题

Here's the translated code without the parts you requested not to translate:

我一直在使用Scala Cats最终陷入了隐式implicits和类型约束type constraints的困境

假设以下定义

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显示错误无法解析符号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)
      //            ^
      //            |--- 无法解析符号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](...)`返回一个包装的`List``F[List[Rate.Pair]]`鉴于对`F[_]: Monad`的类型约束我假设Scala应该能够推断出`F extends Monad`并找到所有`Monad`的方法包括`flatMap`)。

整个`for`推导都在相同的`F[_]`上下文中工作因此似乎不是类型不匹配的问题

我尝试展开隐式和`for`推导因此得到了这个不太美观的实现

```scala
    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

<details>
<summary>英文:</summary>
I&#39;ve been playing with scala cats and ended up stuck with implicits and type constraints.
Assume the following definitions:
```scala
trait Client[F[_]] {
def fetchPossiblePairs(fetcher: Uri =&gt; F[List[String]]): F[List[Rate.Pair]]
def fetchQuotes(currencyPairs: List[Rate.Pair], fetcher: Uri =&gt; 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]) =&gt; acc.updated(rate.pair, rate))
}

The following implementation works, but looks ugly and not really up to the standards:

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 =&gt; client.fetchQuotes(currencyPairs, uri =&gt; client.convertRate(uri)))
      .map(quotes =&gt; updateCache(existingRates, quotes))
  }
}

Making it more conventional, using the for comprehension, IDE shows an error 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 &lt;- getCurrencyPairs(client, existingRates)
      //            ^
      //            |--- Cannot resolve symbol flatMap
      //
      rates &lt;- client.fetchQuotes(currencyPairs, uri =&gt; client.convertRate(uri))
    } yield updateCache(existingRates, rates)
}

And SBT shows a slightly different error:

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

My understanding is that the two implementations are the same, just using the different syntactic sugar.

getCurrencyPairs[F[_]: Monad](...) returns a wrapped List, F[List[Rate.Pair]], and given the type constraint on F[_]: Monad I assume Scala should be able to infer F extends Monad and find all the Monad's methods (including flatMap).

The entire for comprehension works within the same context of F[_], hence seems it is not the type mismatch.

I tried to expand the implicits and for comprehension, hence arriving at this ugly implementation:

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

It does not make a lot of sense to have (implicit m: Monad[F[_]]), in my opinion (at least I could not come up with the correct usage for it).

I am not really proficient with Scala implicits, but seems like there is something wrong with my code. Where am I wrong?

The versions I'm using are:

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

答案1

得分: 2

这几乎可以肯定是因为缺少提供该方法的导入。

添加 import cats.syntax.all._

英文:

This is almost certainly due to missing the import that provides the method.

Add import cats.syntax.all._

huangapple
  • 本文由 发表于 2023年6月8日 15:08:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429391.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定