LanguageExt.Core

LanguageExt.Core Traits Domain

Inspired by: https://mmapped.blog/posts/25-domain-types.html

Contents

interface Amount <SELF, SCALAR> Source #

where SELF : Amount<SELF, SCALAR>

A typical use of domain types is representing quantities, such as the amount of money in USD in a bank account, or the file-size in bytes. Being able to compare, add, and subtract amounts is essential.

Generally, we cannot multiply or divide two compatible amounts and expect to get the amount of the same type back.

Unless we’re modeling mathematical entities, such as probabilities or points on an elliptic curve.. Multiplying two dollars by two dollars gives four squared dollars. I don’t know about you, but I’m yet to find a practical use for squared dollars.

Multiplying amounts by a dimensionless number, however, is meaningful. There is nothing wrong with a banking app increasing a dollar amount by ten percent or a disk utility dividing the total number of allocated bytes by the file count.

The appropriate mathematical abstraction for amounts is vector spaces. Vector space is a set with additional operations defined on the elements of this set: addition, subtraction, and scalar multiplication, such that behaviors of these operations satisfy a few natural axioms.

This is the same as VectorSpace but with ordering

Parameters

type SELF

Type implementing this interface

type SCALAR

Scalar units

interface DomainType <SELF> Source #

where SELF : DomainType<SELF>

Fundamental base-trait for implementing domain-types. This is the basis for Identifier, Locus, VectorSpace, and Quantity. It allows the derived types to be safely instantiated from simpler values, like int, float, etc. And, to be converted back from the domain-type to the simpler representation.

Parameters

type SELF

Type implementing this interface

interface DomainType <SELF, REPR> Source #

where SELF : DomainType<SELF, REPR>

Fundamental base-trait for implementing domain-types. This is the basis for Identifier, Locus, VectorSpace, and Quantity. It allows the derived types to be safely instantiated from simpler values, like int, float, etc. And, to be converted back from the domain-type to the simpler representation.

Parameters

type SELF

Type implementing this interface

type REPR

Underlying representation

Methods

method Fin<SELF> From (REPR repr) Source #

Creates a domain value from its representation value

Parameters

returns

Either an Error or a validly constructed SELF.

method SELF FromUnsafe (REPR repr) Source #

Creates a domain value from its representation value

Parameters

returns

Either throws an exception or returns a validly constructed SELF.

interface Identifier <SELF> Source #

where SELF : Identifier<SELF>

One of the most common uses of domain types is a transparent handle for an entity or an asset in the real world, such as a customer identifier in an online store or an employee number in a payroll application. I call these types identifiers.

Identifiers have no structure, i.e., we don’t care about their internal representation. The only fundamental requirement is the ability to compare values of those types for equality. This lack of structure suggests an appropriate mathematical model for such types: a set, a collection of distinct objects.

Parameters

type SELF

Type implementing this interface

interface Locus <SELF, DISTANCE, DISTANCE_SCALAR> Source #

where SELF : Locus<SELF, DISTANCE, DISTANCE_SCALAR>
where DISTANCE : Amount<DISTANCE, DISTANCE_SCALAR>

Working with space-like structures, such as time and space, poses an interesting challenge. Spaces have two types of values: absolute positions and relative distances.

Positions refer to points in space, such as timestamps or geographical coordinates. Distances represent a difference between two such points.

Some natural languages acknowledge the distinction and offer different words for these concepts, such as o’clock vs. hours.

While distances behave the same way as Amount, positions are trickier. We can compare, order, and subtract them to compute the distance between two points. For example, subtracting 5 am on Friday from 3 am on Saturday gives us twenty-two hours. Adding or multiplying these dates makes no sense, however. This semantic demands a new class of types, loci (plural of locus).

We can view each position as a distance from a fixed origin point. Changing the origin or the distance type calls for a new locus type.

Parameters

type SELF

Type implementing this interface

type DISTANCE

Additive units

type DISTANCE_SCALAR

Distance scalar units

interface VectorSpace <SELF, SCALAR> Source #

where SELF : VectorSpace<SELF, SCALAR>

A typical use of domain types is representing quantities, such as the amount of money in USD in a bank account, or the file-size in bytes. Being able to compare, add, and subtract amounts is essential.

Generally, we cannot multiply or divide two compatible amounts and expect to get the amount of the same type back.

Unless we’re modeling mathematical entities, such as probabilities or points on an elliptic curve.. Multiplying two dollars by two dollars gives four squared dollars. I don’t know about you, but I’m yet to find a practical use for squared dollars.

Multiplying amounts by a dimensionless number, however, is meaningful. There is nothing wrong with a banking app increasing a dollar amount by ten percent or a disk utility dividing the total number of allocated bytes by the file count.

The appropriate mathematical abstraction for amounts is vector spaces. Vector space is a set with additional operations defined on the elements of this set: addition, subtraction, and scalar multiplication, such that behaviors of these operations satisfy a few natural axioms.

Parameters

type SELF

Type implementing this interface

type SCALAR

Scalar units