❮❮❮ ❮❮❮   ❯❯❯ ❯❯❯
Bonsai
Thoughts about a tree serialisation library.

Tags: data
Reading time: 5 min.

These are some thoughts about the design of a functional library to serialize partially abstract finite tree-shaped data.

Type context

Representation of representation mappings (RoRM)

Type representation

type Label = string

type Shape prim =
  | Prim of prim
  | Tuple of Array (Shape prim)
  | Array of (Shape prim)
  | Variant of Map (Label, Shape prim)
  | Record of Map (Label, Shape prim)

type PrimType =
  | PT_Unit
  | PT_Int
  | PT_Bool
  | ...

type YetUnresolved =
  | Prim of PrimType
  | Unknown of App // If an abstract type is not in the RoRM.
  | Recursion of App // If an abstract type is encountered twice along the same branch of the shape tree.

type Stepwise =
  | Prim of PrimType
  | Unknown of App
  | Recursion of App
  | NextStep of App * (Set App) // Type to respresent/expand next and the set of abstract types encoured along the branch to here.

Example

Given the setup

type PrimType =
  | PT_Unit
  | PT_Int
  | PT_Bool

let RoRM : Map (App, App) =
  {
    Map ('a, 'b) -> Array ('a * 'b)
    Abs1 -> int * (Abs2 bool)
    Abs2 'a -> bool * 'a
  }

let steps = expansionSteps RoRM

The derivations are

steps unit = [
  NextStep (unit, Set []),
  Prim PT_Unit,
  ]

steps (array int) = [
  NextStep (array int, Set []),
  Array (NextStep int, Set []),
  Array (Prim PT_Int)
]

steps { A : bool, b : int * bool } = [
  NextStep ({ A : bool, b : int * bool }, Set []),
  Record { "A" -> (NextStep bool, Set []), "B" -> (NextStep (int * bool), Set [])},
  Record { "A" -> Prim PT_Bool, "B" -> Tuple [NextStep (int, Set []), NextStep (bool, Set [])]},
  Record { "A" -> Prim PT_Bool, "B" -> Tuple [Prim PT_Int, Prim PT_Bool]},
]

steps Abs1 = [
  NextStep (Abs1, Set []),
  NextStep (int * Abs2 bool, Set [Abs1]),
  Tuple [NextStep (int, Set [Abs1]), NextStep (Abs2 bool, Set [Abs1])],
  Tuple [Prim PT_Int, NextStep (bool * bool, Set [Abs1, Abs2])],
  Tuple [Prim PT_Int, Tuple [NextStep (bool, Set [Abs1, Abs2]), NextStep (bool, Set [Abs1, Abs2])]],
  Tuple [Prim PT_Int, Tuple [Prim PT_Bool, Prim PT_Bool]],
] // int * (bool * bool)

Value representation

type PrimVal =
  | PV_Unit 
  | PV_Int of int
  | PV_Bool of bool
  | ...

type RepValue = 
  | Prim of prim
  | Tuple of Array RepValue
  | Array of Array RepValue
  | Variant of Label * RepValue
  | Record of Map (Label, RepValue)

Gotcha

let crazy : RepValue = Array [PV_Unit, PV_Int 2, PV_Int 2]
// not possible as represent t
let t : Array int = [1, 2, 3, 4]
let r : RepValue = Array [PV_Int 1, PV_Int 2, PV_Int 3, PV_Int 4]
let t : Array (int * bool) = [(1, true), (2, false), (3, true)]
let r : RepValue = Array [Tuple [PV_Int 1, PV_Bool true], Tuple [PV_Int 2, PV_Bool false], Tuple [PV_Int 3, PV_Bool true]]

Recursive types

type rec List a =
  | Nil
  | Cons of a, * (List a)