Skip to content

A set of type providers for F# that aims to implement an approximation of refinement types.

License

Notifications You must be signed in to change notification settings

aggieben/ConstrainedTypes

Repository files navigation

ConstrainedTypes

.NET Core

One of the features I've often wanted in F♯ was an ability to more directly represent "sub-types" that are better tailored to some domain model than the built-in types. In type theory this is called a refinement type. For example, it's often the case that strings are stored in the database, but they are also just as often limited in length. That tends to impose a constraint all across the domain, and so what I'd like to do in my domain model is capture that constraint so that invalid states are unrepresentable.

This package implements type providers that allow the user to essentially generate these psuedo-refinement types at compile-time. I hesitate to call these types true refinement types because they don't do much to increase how much the compiler can do for you at compile time other than generate the types you need based on the specific types of constraints specified via the type provider mechanism. It seems to me that true refinement types would require direct compiler support, which simply isn't present in F♯. However, for the sake of domain modeling these types will get you most of the benefits of refinement types.

For example, if you have a 64-byte string in the database, one can effectively represent it thusly using the BoundedString type provider:

open ConstrainedTypes

type BoundedString64 = BoundedString<64>

type DomainModel =
    { Pk : uint64
      Name : BoundedString64 }

In this model, you can be sure that there is never a string longer than 64 characters stored under the to the DomainModel.Name label. The BoundedString provider can be used to arbitrarily generate types for varying lengths, as required.

Type Providers in this package:

BoundedString

See example above

RangedInt

Can be used like this:

open ConstrainedTypes

// this type can be used wherever you might have previously used an int.
type IntegersBetween0And100 = RangedInt<0,100>

Note about versions

I plan to be consistent with SemVer, however any version under 1.0 may fudge the rules a bit (i.e., I may make a breaking change between 0.2 and 0.3).

About

A set of type providers for F# that aims to implement an approximation of refinement types.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages