2

A 和我正在使用 circe 对一些 ADT 进行编码/解码,我们遇到了一些我们根本不了解的功能。circe 文档中给出的示例按预期工作,但在深入研究后 - 不清楚为什么解码示例有效,因此我们很难推理如何在需要时进行修改。

功能(来自关于 ADTs 的 Circe 示例):

import cats.syntax.functor._
import io.circe.{ Decoder, Encoder }, io.circe.generic.auto._
import io.circe.syntax._

object GenericDerivation {
  // Encoder Redacted

  implicit val decodeEvent: Decoder[Event] =
    List[Decoder[Event]](
      Decoder[Foo].widen,
      Decoder[Bar].widen,
      Decoder[Baz].widen,
      Decoder[Qux].widen
    ).reduceLeft(_ or _)
}

我明白了 - 基本上是从这个列表中选择第一个工作的解码器 - 有道理但是(!)

or似乎是一个采用名称参数的一元函数。类型签名是:

final def or[AA >: A](d: => Decoder[AA]): Decoder[AA]

并且reduceLeft(来自 IterableOnce)需要一个二元函数。类型签名是: def reduceLeft[B >: A](op: (B, A) => B): B

然后我的大脑爆炸了。我显然错过了一些东西,无法弄清楚。

该示例最明确地适用于转换 ADT。or鉴于该功能似乎不符合所需的类型,为什么/如何工作reduceLeft

4

2 回答 2

7

or是一个参数的方法,但不要忘记this.

decoder1.or(decoder2)(aka decoder1 or decoder2) 是关于decoder1,的二元函数decoder2

+也是一个参数的方法

final abstract class Int private extends AnyVal {
  ...

  /** Returns the sum of this value and `x`. */
  def +(x: Int): Int

  ...
}

但您仍然可以添加两个Ints: 1 + 1aka 1.+(1).

所有方法都有一个比其签名中列出的多一个“参数”,即this.

(所有普通参数都是静态this解析,动态解析。)

于 2020-07-23T15:59:08.067 回答
2

考虑以下简化的类比

case class Score(v: Double) {
  def add(that: Score): Score = Score(this.v + that.v)
}

val l = List[Score](Score(1.1), Score(2.2), Score(0.1))

l.reduceLeft((a: Score, b: Score) => a.add(b))  // unsugared
l.reduceLeft((a: Score, b: Score) => a add b)   // infix notation
l.reduceLeft(_ add _)                           // anonymous function placeholder parameter

注意中缀表示法匿名函数占位符参数的使用

于 2020-07-23T16:12:28.300 回答