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.