无法理解Writes中contramap的逻辑

Unable to understand the logic of contramap in Writes

我无法理解 contramap 在编写具有单个字段 jsoncase class 时如何工作。

说我有一个案例 class,我想创建它 json

case class SomeThingContainer (something:SomeThing)

我会这样写write

 implicit val somethingContainerWrites:Writes[SomeThingContainer] = (
    (JsPath \ "something").write[Something]
 ).contramap{(somethingContainer:SomeThingContainer)=>somethingContainer.something}

如果我有如下模型, val somethingContainerVariable = SomethingContainer(something)

在应用程序的某处,我会调用 toJson[SomeThingContainer] 将模型转换为 Json。这将寻找隐含的 Writes[SomeThingContainer],即 somethingContainerWrites。从这里开始,JSON 是如何创建的?如果有多个字段,我可以稍微理解 unapply _ 是如何工作的,但我无法理解 contramap 如何发挥它的魔力。

contramap 用于组合函子。

A Writes 是一个(逆变)函子 X => JsValue。 (它知道如何从给定的 X 创建 JsValue)

显然,您已经在某处定义了 Writes[Something](因为您正在调用 JsPath.write[Something],这隐含地需要它)。

在括号内,您创建一个新的 Writes[Something],它只使用前者将 Something 写入 JSON 对象中的不同路径。

现在,要能够从 SomeThingContainer 创建 JsValue,您需要做的就是将 SomeThingContainer 转换为 Something -- 因为您手边已经有了一个 Writes[Something] -- 并使用它。

这就是 contramap 调用的作用:根据您定义的 Writes[Something],它会创建一个新的 Writes[SomeThingContainer],当给定一个 SomeThingContainer 时,它首先调用给定的 [=42] =] 产生一个 Something。然后,它用那个调用 Writes[Something]

为了说明,contramap 做了什么:

Writes[X]: Functor[X => JsValue]
C: Y => X
Writes[X].contramap(C) <==> Writes[Y]: Functor[Y => X => JsValue]