`circe`类型级Json =>一个函数?

Kev*_*ith 4 scala argonaut circe

使用circe或者argonaut,我怎么能写一个Json => A(注释 - Json可能不是类型的名称)ASSN类给出的位置:

  // A USA Social Security Number has exactly 8 digits.
  case class SSN(value: Sized[List[Nat], _8])
Run Code Online (Sandbox Code Playgroud)

伪代码:

// assuming this function is named f

f(JsArray(JsNumber(1)))A因为它的大小是1而不会成为一个

f(JsArray(JsNumber(1), ..., JsNumber(8))) === SSN(SizedList(1,...,8))

Tra*_*own 5

circe(目前)不提供实例Sized,但可能应该提供实例.在任何情况下,你都可以直截了当地写自己的:

import cats.data.Xor
import io.circe.{ Decoder, DecodingFailure }
import shapeless.{ Nat, Sized }
import shapeless.ops.nat.ToInt
import shapeless.syntax.sized._

implicit def decodeSized[L <: Nat, A](implicit
  dl: Decoder[List[A]],
  ti: ToInt[L]
): Decoder[Sized[List[A], L]] = Decoder.instance { c =>
  dl(c).flatMap(as =>
    Xor.fromOption(as.sized[L], DecodingFailure(s"Sized[List[A], _${ti()}]", c.history))
  )
}
Run Code Online (Sandbox Code Playgroud)

我已将此限制为List表示形式,但如果您愿意,可以使其更具通用性.

现在你可以SSN像这样编写你的实例(请注意我使用的是Int代替Nat单个数字,因为一旦你得到静态输入的东西,Nat它就不值得了):

case class SSN(value: Sized[List[Int], Nat._8])

implicit val decodeSSN: Decoder[SSN] = Decoder[Sized[List[Int], Nat._8]].map(SSN(_))
Run Code Online (Sandbox Code Playgroud)

然后:

scala> import io.circe.jawn.decode
import io.circe.jawn.decode

scala> decode[SSN]("[1, 2, 3, 4, 5, 6, 7, 8]")
res0: cats.data.Xor[io.circe.Error,SSN] = Right(SSN(List(1, 2, 3, 4, 5, 6, 7, 8)))

scala> decode[SSN]("[1, 2, 3, 4, 5, 6, 7]")
res1: cats.data.Xor[io.circe.Error,SSN] = Left(DecodingFailure(Sized[List[A], _8], List()))
Run Code Online (Sandbox Code Playgroud)

如果你真的想要一个,Json => SSN你可以这样做:

val f: Json => SSN = Decoder[SSN].decodeJson(_).valueOr(throw _)
Run Code Online (Sandbox Code Playgroud)

但这并不是对circe的惯用.