2016-08-27 2 views
4

Использование circe или argonaut, как я могу написать Json => A (примечание - Json не может быть именем типа), где A дается SSN класса:`circe` Type-level Json => Функция?

// 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))

+1

https://en.wikipedia.org/wiki/Social_Security_number https://www.ssa.gov/policy/docs/ssb/v69n2/v69n2p55.html –

+0

Ха-ха - хороший улов. 9 цифр ssn, а не 8. –

ответ

5

Кирка не (в настоящее время) обеспечивают экземпляры для 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 _) 

Но это не идиоматическое использование цирце.

+0

Спасибо, Тревис. Для тех, кто интересуется этим вопросом, вы также можете найти http://stackoverflow.com/questions/39183907/class-with-list-of-nats-between-0-and-2. Я пытаюсь уточнить использование 'List [Int]' to 'List [A]' где 'A' состоит из' Nat ''s меньше или равно 2. –

Смежные вопросы