재귀 유형

10688 단어 functionalscalaadt
Kodumaro의 원본 게시물 .


Scala : JSON 표현에서 순환 참조 문제가 발생했습니다.

직렬화 및 역직렬화에 Gson을 사용했지만(자세한 내용은 설명하지 않음) 언어 생태계 내에서 모델을 표현하는 방법은 무엇입니까?

나는 Gson 문서를 따를 수 있고 pojos (case classes이 좋습니다)를 사용할 수 있지만 더 유연한 것이 필요했습니다.

정수, 문자열, 큰 숫자 등과 같은 기본 언어를 사용하기로 결정했습니다.

그래서 나는 그것을 다루기 위해 몇 가지 유형을 만들었습니다.

type unroll[+A] = A
type JValue = unroll[_ <: Any]
type JArray = Seq[JValue]
type JObject = String Map JValue


나쁘지 않습니다. 복잡한 객체를 JValue 변수에 담을 수 있습니다.

val data: JValue = Map(
  "x" -> 3,
  "y" -> 4,
  "name" -> "test",
  "list" -> Seq("zero", 1, 2, 3, true),
)


그러나 다음과 같은 이상한 일이 일어나기 시작했습니다.

val element: JValue = <data>This is an XML node</data>


그것은 충돌해야합니다! 그러나 NodeSeqAny 의 하위 클래스이기 때문에 그렇지 않습니다.

더 엄격한 것이 필요했습니다.

도티 입력



이제 시도했습니다 Scala 3, codename Dotty .

내 첫 번째 실패한 시도는 다음과 같습니다.

type JNull = Unit
type JValue = Int | BigDecimal | String | Boolean | JNull | Seq[JValue] | String Map JValue


그리고 Dotty는 내 계획에 제동을 걸었습니다.

Illegal cyclic type reference: alias Map[Int | BigDecimal | String | Boolean | JNull | Seq[JValue] | String, JValue] of type JValue refers back to the type itself.



그런 다음 this strange solution을 쳤습니다.

type Rec[F[_], A] = A match {
  case Int => Int | F[Rec[F, Int]]
  case _ => A | F[Rec[F, A]]
}


Jasper M은 Scalatype erasure를 활용하여 런타임LazyRef을 생성할 것을 제안합니다. 그래서 나는 조언을 따랐다.

type JNull = Unit
type JPrimitive = Int | BigDecimal | String | Boolean | JNull

type Rec[JArray[_], JObject[_], A] = A match
  case JPrimitive => JPrimitive | JArray[Rec[JArray, JObject, JPrimitive]] | JObject[Rec[JArray, JObject, JPrimitive]]
  case _          => A          | JArray[Rec[JArray, JObject, A]]          | JObject[Rec[JArray, JObject, A]]

type JValue = Rec[Seq, [A] =>> String Map A, JPrimitive]


그리고 보이스 라! 그것은 꽤 잘 작동합니다!

// Okay, unit represents null
var x: JValue = ()

// Also okay
x = true

// OMG! Still okay!
x = Map(
  "x" -> 3,
  "y" -> 4,
  "name" -> "test",
  "list" -> Seq("zero", 1, 2, 3, true),
)

// It throws an exception
x = <data>nope</data>

// If -Yexplicit-nulls is enabled, it throws an exception too
x = null


이제 JValue는 훨씬 더 엄격해지고 WeakRef는 재귀 유형을 가능하게 했습니다.

좋은 웹페이지 즐겨찾기