Search code examples
ocamlrecordmutablecircular-reference

using record field in other field of the same record


I wonder if it is possible in OCaml to use one field of record in the other field in the same record.

Basicaly, I have field with function in which I would like to use also other, values, fields of the same record so when the value change the function will use the new value.

I can do it with setting the function field mutable and update it after the record is created e.g.

type 'a cell =
  { mutable value: 'a
  ; mutable fn: unit -> 'a }

let create_cell ~(value : 'a) : 'a cell =
  let c = {value; fn= (fun () -> value + 42)} in
  let _ = c.fn <- (fun () -> c.value + 42) in
  c

I was wondering if it is possible without fn field being mutable and in one go.


Solution

  • You can use let rec to make the function refer to the record it is part of:

    # type 'a cell = { mutable value : 'a ; fn : unit -> 'a };;
    type 'a cell = { mutable value : 'a; fn : unit -> 'a; }
    # let rec r = { value = 14; fn = fun () -> r.value + 14 };;
    val r : int cell = {value = 14; fn = <fun>}
    # r.fn ();;
    - : int = 28
    # r.value <- 10;;
    - : unit = ()
    # r.fn ();;
    - : int = 24
    

    If I understand correctly, this what you'd like to do.

    So then your create_cell function might look like this:

    let create_cell ~(value : 'a) : 'a cell =
      let rec c = {value; fn= (fun () -> c.value + 42)} in
      c
    

    It seems to work:

    # let mycell = create_cell ~value: 88;;
    val mycell : int cell = {value = 88; fn = <fun>}
    # mycell.fn ();;
    - : int = 130
    # mycell.value <- 100;;
    - : unit = ()
    # mycell.fn ();;
    - : int = 142