`circe` 类型级别 Json => 函数?
`circe` Type-level Json => A Function?
使用circe
或argonaut
,我如何写一个Json => A
(注意-Json
可能不是类型的名称)其中A
由 SSN
class:
给出
// A USA Social Security Number has exactly 8 digits.
case class SSN(value: Sized[List[Nat], _8])
?
伪代码:
// assuming this function is named f
f(JsArray(JsNumber(1)))
将无法成为 A
,因为它的大小为 1,而
f(JsArray(JsNumber(1), ..., JsNumber(8)))
=== SSN(SizedList(1,...,8))
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))
)
}
我已将其限制为 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(_))
然后:
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()))
如果你真的想要 Json => SSN
你可以这样做:
val f: Json => SSN = Decoder[SSN].decodeJson(_).valueOr(throw _)
但这并不是 circe 的惯用用法。
使用circe
或argonaut
,我如何写一个Json => A
(注意-Json
可能不是类型的名称)其中A
由 SSN
class:
// A USA Social Security Number has exactly 8 digits.
case class SSN(value: Sized[List[Nat], _8])
?
伪代码:
// assuming this function is named f
f(JsArray(JsNumber(1)))
将无法成为 A
,因为它的大小为 1,而
f(JsArray(JsNumber(1), ..., JsNumber(8)))
=== SSN(SizedList(1,...,8))
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))
)
}
我已将其限制为 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(_))
然后:
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()))
如果你真的想要 Json => SSN
你可以这样做:
val f: Json => SSN = Decoder[SSN].decodeJson(_).valueOr(throw _)
但这并不是 circe 的惯用用法。