I have a discriminated union, such as
type Dish =
| Eggs
| Spam of Dish
This is basically a linked list, without any content, e.g. Spam(Spam(Spam(Eggs))). I want to strictly perform a computation on this structure, such as counting the length, and memorize the result. In a normal type, I’d use class-local let bindings, but those aren’t available in discriminated unions.
One way to do this would be,
type Count = int
type Dish =
| Eggs
| Spam of Dish * Count
But this is really messy, when the data I need is easily computable, but I still hope there is a better way (without using external mutable constructs).
After reviewing the answers, I’ve decided to go with a model that seems the least obtrusive to me. I’ve used a modified object to demonstrate how it would work in a slightly more complex scenario.
Dish(or in the example,Stack) continues to exist.lengthdoesn’t appear in the union definition at all, nor is it provided by any constructor, just as it should be.However, having thought about it, by using a static weaver such as Afterthought it might be possible to replace any method such as:
With a
private readonly Lazy<int> __lengthinitialized in the constructor with a delegate that executes the above code, and change the actual content of the method to simply invoking__length.Value.While F# doesn’t allow union types to contain fields, possibly for very valid reasons, I highly doubt the IL would have such restrictions.
In fact, it would be possible to do a lot of things using some IL manipulation. Maybe it’s something to think about.