Recursion models

There's two ways to define recursive models:

recursive

available since: 1.0.0

Context-free recursions are more powerful than regular recursions.

You can write some nastily complex data structures using the recursive constructor

Example:

Query:
e.data(m.recursive("S", {
  • S: m.struct({
    • foo: m.recurse("T"),
    • bar: m.recurse("U"),
    }
    )
    ,
  • T: m.struct({
    • bar: m.recurse("U"),
    • zap: m.optional(m.recurse("S")),
    }
    )
    ,
  • U: m.int32(),
}
)
)
Result:
{ "recursive": { "models": { "S": { "struct": { "bar": { "recurse": "U" }, "foo": { "recurse": "T" } } }, "T": { "struct": { "bar": { "recurse": "U" }, "zap": { "optional": { "recurse": "S" } } } }, "U": { "int32": {} } }, "top": "S" } }
Notes:

Parameter top defines which model is takes as entry point. As you can see, mutually-recursive structures are possible.

Example:

Query:
e.data(d.struct({
  • foo: d.struct({
    • bar: d.int32(1),
    • zap: d.struct({
      • foo: d.struct({
        • bar: d.int32(2),
        • zap: d.struct({
          • foo: d.struct({
            • bar: d.int32(3),
            }
            )
            ,
          • bar: d.int32(3),
          }
          )
          ,
        }
        )
        ,
      • bar: d.int32(2),
      }
      )
      ,
    }
    )
    ,
  • bar: d.int32(1),
}
)
)
Result:
{ "bar": 1, "foo": { "bar": 1, "zap": { "bar": 2, "foo": { "bar": 2, "zap": { "bar": 3, "foo": { "bar": 3 } } } } } }
Notes:

A recursive content based on the model definition above

Example:

Query:
e.data(m.recursive("A", {
  • A: m.recurse("B"),
  • B: m.recurse("A"),
}
)
)
Result:
{ "recursive": { "models": { "A": { "recurse": "B" }, "B": { "recurse": "A" } }, "top": "A" } }
Notes:

It is an error to build a endlessly recursing models like this example

recursion

available since: 1.0.0

Regular recursion allows you to define recursive data structures that are self-similar, using the recursion constructor.

For example: a struct that contains another struct of the same shape, which in turn contains another of itself, and so on.

Example:

Query:
e.data(m.recursion("self", m.struct({
  • payload: m.int32(),
  • next: m.optional(m.recurse("self")),
}
)
)
)
Result:
{ "recursion": { "label": "self", "model": { "struct": { "next": { "optional": { "recurse": "self" } }, "payload": { "int32": {} } } } } }
Notes:

A struct model composed of two keys, where the key 'payload' is of type int32 and 'next' is optional and again this same struct with the same shape

Example:

Query:
e.data(d.struct({
  • payload: d.int32(1),
  • next: d.struct({
    • payload: d.int32(2),
    • next: d.struct({
      • payload: d.int32(3),
      }
      )
      ,
    }
    )
    ,
}
)
)
Result:
{ "next": { "next": { "payload": 3 }, "payload": 2 }, "payload": 1 }
Notes:

A recursion content based on the model definition above