【问题标题】:Implicits resolution with Scala-cats使用 Scala-cats 隐式解析
【发布时间】:2019-12-24 09:31:23
【问题描述】:

示例取自Tagless Final in Mastering Functional Programming:

trait Capabilities[F[_]] {
  def resource(name: String): F[String]
  def notify(target: String, text: String): F[Unit]
}

import cats.Monad

def income[F[_]](implicit M: Monad[F], C: Capabilities[F]): F[Unit] =
  for {
    contents <- C.resource("sales.csv")
    total = contents
      .split("\n").toList.tail  // Collection of lines, drop the CSV header
      .map { _.split(",").toList match  // List[Double] - prices of each of the entries
    { case name :: price :: Nil => price.toDouble }
    }
      .sum
    _ <- C.notify("admin@shop.com", s"Total income made today: $total")
  } yield ()

为了编译,我必须包括:

import cats.implicits._

没有这个,我得到一个错误:

错误:(21, 27) 值映射不是类型参数 F[String] 的成员 内容

两个问题:

  1. F 的类型事先未知。但是有MonadCapabilitiesF 定义implicitly。为什么 Scala 编译器在没有从猫中隐式导入的情况下无法识别它。
  2. 通常我更喜欢找到某个类型,而不是从cats 导入所有东西。例如,更准确地说,只导入cats.instances.list._。来自cats.implicits._ 的 Scala 编译器究竟使用了什么来编译这段代码?更重要的是,您使用什么算法来找到它?
  3. 我还发现,如果我添加-Xprint-args 选项,即使没有cats.implicits._ 导入,也可以成功编译代码。你能解释一下,它是如何影响它的吗?

【问题讨论】:

    标签: scala monads implicit scala-cats for-comprehension


    【解决方案1】:
    1. 没有隐式导入,Scala 编译器无法识别的只是语法。无需导入即可正确解析实例(由于隐式参数)。

    2. cats.implicits._ 中,你实际上只使用了

      import cats.syntax.functor._
      import cats.syntax.flatMap._
      
    3. https://github.com/scala/scala/pull/5909

      该选项的行为类似于-Xshow-phases 并在打印后停止编译器


    无需导入语法即可编写

    def income[F[_]](implicit M: Monad[F], C: Capabilities[F]): F[Unit] =
      M.flatMap(C.resource("sales.csv"))(contents => {
        val total = contents
          .split("\n").toList.tail // Collection of lines, drop the CSV header
          .map {
            _.split(",").toList match // List[Double] - prices of each of the entries
              { case name :: price :: Nil => price.toDouble }
          }
          .sum
        M.map(C.notify("admin@shop.com", s"Total income made today: $total"))(_ => ())
      })
    

    【讨论】:

    • 谢谢!问题是:我认为,Scala可以通过签名识别,当方法被调用时,某些隐式实例将在范围内。并且也应该明白,如果对于F类型——Monad存在,它必须有,什么时候调用map/flatMap等函数。
    • @Alexandr 是的,但是“必须有,什么时候调用 map/flatMap 和其他函数”意味着你可以像 Monad[F].flatMap(fa)(f), Functor[F].map(fa)(f) 那样调用它们...如果你想像这样调用它们fa.flatMap(f), fa.map(f) ...,那么你还应该导入语法。
    • 谢谢你,Dmytro,澄清它。在这种情况下从来没有想过它。
    • 您能否说明,当未导入语法时,如何在 for-comprehension 中准确调用 contents &lt;- C.resource("sales.csv")。只是 vai Monad.flatMap 函数。
    • @Alexandr gist.github.com/loicdescotte/4044169我更新了我的答案。
    猜你喜欢
    • 2019-09-23
    • 1970-01-01
    • 1970-01-01
    • 2015-12-03
    • 2017-10-11
    • 2012-01-27
    • 2020-12-04
    • 2020-11-24
    • 2013-12-27
    相关资源
    最近更新 更多