jaredramirez/rescript-json

Recursive records

Closed this issue · 5 comments

Hey, library looks great.

Is possible to create a decoder for the following?

type rec t = { id: string, child: t }

Thanks

Hey there!

Yes, this is possible with a minor change to your type. It would need to be:

type rec t = { id: string, child: option<t> }

It doesn't have to be an option, but the child t needs to be wrapped in some type that has an empty state otherwise it'd be infinitely recursive.

With the type above, you can do:

let rec decoder: unit => Json.Decode.t<t> = () => {
  open Json.Decode
  map2(
    field("id", string),
    option(field("child", decoder())),
    ~f=(id, optChild) => { id: id, child: optChild }
  )
}

Unfortunately, the way Rescript's recursive syntax works, the recursive value has to be a function so our decoder here takes unit.

I think there's a possibility for using lazy here too, but that's probably a separate issue/feature.

Closing this for now. If the above doesn't answer your question feel free to reopen.

Hey, sorry for reopening this but when I try to use the above it blows the stack

Yeah, it blows the stack indeed.

Did any of you guys figure out another way to do this?

@samtefey @jaredramirez

I just noticed elm json has a lazy decoder. What would be necessary for us to implement it? I can try that

Hey, looks like I made it:

let lazy_ = thunk => Json.Decode.andThen(succeed(), ~f=thunk)

type rec comment = {message: string, responses: array<comment>}

let rec commentDecoder: unit => Json.Decode.t<comment> = () => {
  open! Json.Decode

  succeed((msg, responses) => {message: msg, responses: responses})
  ->andMap(field("message", string))
  ->andMap(field("responses", array(lazy_(_ => commentDecoder()))))
}

// or

let rec commentDecoder: unit => Json.Decode.t<comment> = () => {
  open! Json.Decode

  map2(field("message", string), field("responses", array(lazy_(_ => commentDecoder()))), ~f=(
    message,
    responses,
  ) => {message: message, responses: responses})
}

Yeah, that's working. ✅