Home > OS >  Self-reference during the creation of class or record in F#
Self-reference during the creation of class or record in F#

Time:11-13

I study F# and do so by solving Advent of Code 2018. For one task I want to write a looped linked list: each node should have links to the next and to the previous node. A list of one node is valid, that node is both next and previous to itself.

This is the record that I came up with initially:

type Node = {
    mutable Next: Node
    mutable Prev: Node
    Value: int
}

But then I found out that I can't instantiate the initial Node with a value of 0 and links to itself. Then I tried to write a class, but still didn't manage to write a legal constructor that I need. Here's my attempt:

type Node(value: int, next: Node, prev: Node) as this =
    let mutable _next = next
    let mutable _prev = prev
    let _value = value

    private new value =
        Node(value, this, this) // this line is illegal

    member this.Next
        with get() = _next
        and set(value) = _next <- value

    member this.Prev
        with get() = _prev
        and set(value) = _prev <- value

    member this.Value
        with get() = _value

    static member Initial value =
        Node(value)

Here is a C# equivalent of what I want to achieve:

    public class Node {
        public Node Next { get; set; }
        public Node Prev { get; set; }
        public int Value { get; }

        public Node(int value, Node next, Node prev)
        {
            Value = value;
            Next = next;
            Prev = prev;
        }
        
        private Node(int value)
        {
            Value = value;
            Next = this;
            Prev = this;
        }

        public static Node Initial(int value)
        {
            return new Node(value);
        }
    }

I know I could just make Next and Prev of type Node option but that would mean worsening my code because of syntax limitations. There should be something in F# syntax that I'm missing. Tried googling and searching for a similar question, but to no avail.

How do I set a link to itself during the creation of a record or class in F#?

CodePudding user response:

This can be achieved with a record with mutable fields in the following way:

type Node = {
    mutable Next: Node
    mutable Prev: Node
    Value: int
}
with
static member CreateNew(value) = 
    let node = 
        {
            Next = Unchecked.defaultof<_>
            Prev = Unchecked.defaultof<_>
            Value = value
        }
    node.Next <- node
    node.Prev <- node
    node

Node.CreateNew(1)

You get around the normal non-nullability of records using Unchecked.defaultof<_>. Just make sure you set it to something non-null before you return.

  • Related