DependentTypes
This project is an experiment in bringing dependent types to F#. Dependent typing makes supporting a finer level of type granularity easier.
This library presents two alternate generic dependent types. One taking an input element to the same base type within the dependent type 'T -> 'T, and the other
taking the input type to a new base type 'T1 -> 'T2. Dependent types support the same equality and comparison traits as their base type
('T or 'T2). Extension methods are not yet supported.
The core dependent type
1: 2: |
|
relies on a "constructor" type
1:
|
|
which in turn requires a function 'Config -> 'T1 -> 'T2 option that validates the input element. Another type handles consuming the 'Config parameter.
In practice the construction of a family of dependent types looks like this:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: |
|
Notes:
The full validation function
regExStringVerifyis not shown.The presence of
module DigitsDefis strictly for readability purposes, segregating the "helper" functions and types.- All the helper types must have the same access level as the dependent type.
- Aliasing is optional, but obviously provides better readability.
Yes,
PiTypeis not really a constructor.With possible changes to the F# language, the intervening
'Configconsuming helper type may be superfluous.
Alternate form of dependent types
Alternately, a dependent type that restricts the underlying base type to the input element type requires one less type parameter.
See the Tutorial and sample library of dependent types for an
example of a generic collection type, Set<'T>.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
|
Samples & documentation
Tutorial contains a further explanation of this dependent types library.
-
API Reference contains automatically generated documentation for all types, modules, and functions in the library.
-
The DomainLib project is a sample library of useful dependent types:
trimmed, non-empty, non-null string
non-empty generic set
utc datetime
uppercase Latin string of undetermined or static length
digit string of undetermined or static length
integer restricted to a range
-
The DependentTypesConsole project runs demos on both the
'T1 -> 'T2and'T -> 'Tstyle dependent types. Expecto test projects for both the DependentTypes library and the DomainLib sample dependent types.
Issues
Several issues are available for discussion. Among the most interesting
Contributing and copyright
This library is based on original experiments by @robkuz with the LimitedValue type, Creating Generic Wrappers for Validated Values. Further discussion here
You can report issues, fork the project, and submit pull requests. Please also add tests and samples that can be turned into documentation.
The library is available under Public Domain license, which allows modification and redistribution for both commercial and non-commercial purposes. For more information see the License file in the GitHub repository.
type Regex =
new : pattern:string -> Regex + 2 overloads
member GetGroupNames : unit -> string[]
member GetGroupNumbers : unit -> int[]
member GroupNameFromNumber : i:int -> string
member GroupNumberFromName : name:string -> int
member IsMatch : input:string -> bool + 1 overload
member Match : input:string -> Match + 2 overloads
member MatchTimeout : TimeSpan
member Matches : input:string -> MatchCollection + 1 overload
member Options : RegexOptions
...
--------------------
Regex(pattern: string) : Regex
Regex(pattern: string, options: RegexOptions) : Regex
Regex(pattern: string, options: RegexOptions, matchTimeout: TimeSpan) : Regex
val string : value:'T -> string
--------------------
type string = String
type String =
new : value:char -> string + 7 overloads
member Chars : int -> char
member Clone : unit -> obj
member CompareTo : value:obj -> int + 1 overload
member Contains : value:string -> bool
member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
member EndsWith : value:string -> bool + 2 overloads
member Equals : obj:obj -> bool + 2 overloads
member GetEnumerator : unit -> CharEnumerator
member GetHashCode : unit -> int
...
--------------------
String(value: nativeptr<char>) : String
String(value: nativeptr<sbyte>) : String
String(value: char []) : String
String(c: char, count: int) : String
String(value: nativeptr<char>, startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int) : String
String(value: char [], startIndex: int, length: int) : String
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : String
String.Trim([<ParamArray>] trimChars: char []) : string
Regex.IsMatch(input: string, startat: int) : bool
from Microsoft.FSharp.Core
type DigitsValidator =
inherit PiType<int,string,string>
new : config:int -> DigitsValidator
--------------------
new : config:int -> DigitsValidator
type PiType<'Config,'T,'T2> =
new : config:'Config * vfn:('Config -> 'T -> Option<'T2>) -> PiType<'Config,'T,'T2>
member TryCreate : x:'T -> Option<'T2>
--------------------
new : config:'Config * vfn:('Config -> 'T -> Option<'T2>) -> PiType<'Config,'T,'T2>
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
type ValidDigits =
inherit DigitsValidator
new : unit -> ValidDigits
--------------------
new : unit -> ValidDigits
type ValidDigits2 =
inherit DigitsValidator
new : unit -> ValidDigits2
--------------------
new : unit -> ValidDigits2
type ValidDigits3 =
inherit DigitsValidator
new : unit -> ValidDigits3
--------------------
new : unit -> ValidDigits3
type ValidDigits4 =
inherit DigitsValidator
new : unit -> ValidDigits4
--------------------
new : unit -> ValidDigits4
union case LimitedValue.DependentType: 'T -> LimitedValue<'Validator,'Config,'T>
--------------------
type DependentType<'PiType,'Config,'T,'T2 (requires 'PiType :> PiType<'Config,'T,'T2> and default constructor)> =
| DependentType of 'T2
override ToString : unit -> string
member Value : 'T2
static member ConvertTo : x:DependentType<'x,'y,'q,'r> -> Option<DependentType<'a,'b,'r,'s>> (requires 'x :> PiType<'y,'q,'r> and default constructor and 'a :> PiType<'b,'r,'s> and default constructor)
static member Create : xs:'T list -> DependentType<'PiType,'Config,'T,'T2> list
static member Create : xs:seq<'T> -> seq<DependentType<'PiType,'Config,'T,'T2>>
static member Create : x:'T -> DependentType<'PiType,'Config,'T,'T2>
static member Extract : x:DependentType<'PiType,'Config,'T,'T2> -> 'T2
static member TryCreate : x:'T option -> Option<DependentType<'PiType,'Config,'T,'T2>>
static member TryCreate : x:'T -> Option<DependentType<'PiType,'Config,'T,'T2>>
from Index
type ValidDigits =
inherit DigitsValidator
new : unit -> ValidDigits
--------------------
new : unit -> DigitsDef.ValidDigits
type ValidDigits2 =
inherit DigitsValidator
new : unit -> ValidDigits2
--------------------
new : unit -> DigitsDef.ValidDigits2
type ValidDigits3 =
inherit DigitsValidator
new : unit -> ValidDigits3
--------------------
new : unit -> DigitsDef.ValidDigits3
type ValidDigits4 =
inherit DigitsValidator
new : unit -> ValidDigits4
--------------------
new : unit -> DigitsDef.ValidDigits4
static member DependentType.Create : xs:seq<'T> -> seq<DependentType<'PiType,'Config,'T,'T2>>
static member DependentType.Create : x:'T -> DependentType<'PiType,'Config,'T,'T2>
module Set
from Microsoft.FSharp.Collections
--------------------
type Set<'T (requires comparison)> =
interface IComparable
interface IEnumerable
interface IEnumerable<'T>
interface ICollection<'T>
new : elements:seq<'T> -> Set<'T>
member Add : value:'T -> Set<'T>
member Contains : value:'T -> bool
override Equals : obj -> bool
member IsProperSubsetOf : otherSet:Set<'T> -> bool
member IsProperSupersetOf : otherSet:Set<'T> -> bool
...
--------------------
new : elements:seq<'T> -> Set<'T>
type NonEmptySetValidator =
inherit Validator<unit,Set<int>>
new : unit -> NonEmptySetValidator
--------------------
new : unit -> NonEmptySetValidator
type Validator<'Config,'T> =
new : config:'Config * vfn:('Config -> 'T -> Option<'T>) -> Validator<'Config,'T>
member Validate : x:'T -> Option<'T>
--------------------
new : config:'Config * vfn:('Config -> 'T -> Option<'T>) -> Validator<'Config,'T>
type ValidNonEmptySet =
inherit NonEmptySetValidator
new : unit -> ValidNonEmptySet
--------------------
new : unit -> ValidNonEmptySet
| DependentType of 'T
member Value : 'T
static member ConvertTo : x:LimitedValue<'x,'y,'q> -> Option<LimitedValue<'a,'b,'q>> (requires 'x :> Validator<'y,'q> and default constructor and 'a :> Validator<'b,'q> and default constructor)
static member Create : xs:'T list -> LimitedValue<'Validator,'Config,'T> list
static member Create : xs:seq<'T> -> seq<LimitedValue<'Validator,'Config,'T>>
static member Create : x:'T -> LimitedValue<'Validator,'Config,'T>
static member Extract : x:LimitedValue<'Validator,'Config,'T> -> 'T
static member TryCreate : x:'T -> Option<LimitedValue<'Validator,'Config,'T>>
from Index
type ValidNonEmptySet =
inherit NonEmptySetValidator
new : unit -> ValidNonEmptySet
--------------------
new : unit -> NonEmptySetDef.ValidNonEmptySet