Dependent types tutorial
Trimmed, non-empty, non-null strings
This is an example of passing unit
as the config
.
We will see later that passing a configuration other than unit, (), requires a second level of type inheritance.
Note that the module TrimNonEmptyStringDef
helps format the code for readability. Otherwise it serves no functional purpose.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
|
Generalized and specific type creation
Use the config
input to make more specific types over a generalized validator function.
Construct the DependentType option
one of three ways
mkDependentType
function, requires type hint in let valueTryCreate
for option base types this will lift option to the DependentTypeCreate
is always safe (will not throw), but does not lift option to the DependentType
Note that passing a configuration other than unit, (), requires a second level of inheritance.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: |
|
DependentType.Value
returns the base type value.
TryCreate method
If the base type is an option type, and it was created with TryCreate
, option is lifted to the DependentType itself. If the value is known to be
Some
, the unsafe function Helpers.someValue
may be used to access the value.
If you have already returned the DependentType option Value
, the Helper method flatten
and forceValue
will make your code less verbose.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: |
|
Create method
For all 'T2
base types the Create
method is safe (meaning it will not throw), but for option types if will not lift the option.
Here is an example of a dependent type with a simple 'T2
base type.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: |
|
Base type of discriminated Union
Use F# discriminated union to mimic a type family of arbitrarily many members.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: |
|
Generic dependent types
You can also create generic dependent types.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: |
|
Limit values to ranges
Note that passing a configuration other than unit, (), requires a second level of inheritance.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: |
|
Working with the underlying element
Return the underlying typed element with the extract
function or the Value
property.
DependentType.ToString()
implements the underlying 'T2
element's type ToString()
.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: |
|
DependentPair
Useful for keeing the input element associated with the dependent type.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: |
|
ConvertTo
If the output T2
base type of one depependent type is the input type T1
of another, you can convert elements directly from one type to another.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: |
|
Note: the type hints let s42B : IntegerSignType =
, etc. are usually not necessary in compiled code when using the type's static method, but may be in FSI.
from DependentTypes
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
type NonEmptyValidator =
inherit Pi<unit,string,string option>
new : unit -> NonEmptyValidator
--------------------
new : unit -> NonEmptyValidator
type Pi<'Config,'T,'T2> =
new : config:'Config * pi:('Config -> 'T -> 'T2) -> Pi<'Config,'T,'T2>
member Create : x:'T -> 'T2
--------------------
new : config:'Config * pi:('Config -> 'T -> 'T2) -> Pi<'Config,'T,'T2>
union case SomeDependentType.SomeDependentType: 'T2 -> SomeDependentType<'Pi,'Config,'T,'T2>
--------------------
type SomeDependentType<'Pi,'Config,'T,'T2 (requires 'Pi :> Pi<'Config,'T,'T2 option> and default constructor)> =
| SomeDependentType of 'T2
override ToString : unit -> string
member Value : 'T2
static member ConvertTo : x:SomeDependentType<'x,'y,'q,'r> -> SomeDependentType<'a,'b,'r,'s> (requires 'x :> Pi<'y,'q,'r option> and default constructor and 'a :> Pi<'b,'r,'s option> and default constructor)
static member Create : x:'T -> SomeDependentType<'Pi,'Config,'T,'T2>
static member Extract : x:SomeDependentType<'Pi,'Config,'T,'T2> -> 'T2
static member TryCreate : x:'T -> SomeDependentType<'Pi,'Config,'T,'T2> option
from Tutorial
type NonEmptyValidator =
inherit Pi<unit,string,string option>
new : unit -> NonEmptyValidator
--------------------
new : unit -> TrimNonEmptyStringDef.NonEmptyValidator
type NumRangeValidator =
inherit Pi<(int * int),int,int option>
new : config:(int * int) -> NumRangeValidator
--------------------
new : config:(int * int) -> NumRangeValidator
val int : value:'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
type MaxPos100 =
inherit NumRangeValidator
new : unit -> MaxPos100
--------------------
new : unit -> MaxPos100
from Tutorial
type MaxPos100 =
inherit NumRangeValidator
new : unit -> MaxPos100
--------------------
new : unit -> RangeValidation.MaxPos100
type DateTime =
struct
new : ticks:int64 -> DateTime + 10 overloads
member Add : value:TimeSpan -> DateTime
member AddDays : value:float -> DateTime
member AddHours : value:float -> DateTime
member AddMilliseconds : value:float -> DateTime
member AddMinutes : value:float -> DateTime
member AddMonths : months:int -> DateTime
member AddSeconds : value:float -> DateTime
member AddTicks : value:int64 -> DateTime
member AddYears : value:int -> DateTime
...
end
--------------------
DateTime ()
(+0 other overloads)
DateTime(ticks: int64) : DateTime
(+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : DateTime
(+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : DateTime
(+0 other overloads)
type UtcDateTimeValidator =
inherit Pi<unit,DateTime,DateTime>
new : unit -> UtcDateTimeValidator
--------------------
new : unit -> UtcDateTimeValidator
type ValidUtcDateTime =
inherit UtcDateTimeValidator
new : unit -> ValidUtcDateTime
--------------------
new : unit -> ValidUtcDateTime
union case DependentType.DependentType: 'T2 -> DependentType<'Pi,'Config,'T,'T2>
--------------------
type DependentType<'Pi,'Config,'T,'T2 (requires 'Pi :> Pi<'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> -> DependentType<'a,'b,'r,'s> (requires 'x :> Pi<'y,'q,'r> and default constructor and 'a :> Pi<'b,'r,'s> and default constructor)
static member Create : x:'T -> DependentType<'Pi,'Config,'T,'T2>
static member Extract : x:DependentType<'Pi,'Config,'T,'T2> -> 'T2
static member TryCreate : x:Option<'T> -> DependentType<'Pi,'Config,'T,'T2> option
static member TryCreate : x:'T -> DependentType<'Pi,'Config,'T,'T2> option
from Tutorial
type ValidUtcDateTime =
inherit UtcDateTimeValidator
new : unit -> ValidUtcDateTime
--------------------
new : unit -> UtcDateTimeDef.ValidUtcDateTime
| PositiveInt of int
| Zero of int
| NegativeInt of int
type IntSumTypeDiscriminator =
inherit Pi<unit,int,IntegerOfSign>
new : unit -> IntSumTypeDiscriminator
--------------------
new : unit -> IntSumTypeDiscriminator
from Tutorial
type IntSumTypeDiscriminator =
inherit Pi<unit,int,IntegerOfSign>
new : unit -> IntSumTypeDiscriminator
--------------------
new : unit -> SumType.IntSumTypeDiscriminator
module Set
from Microsoft.FSharp.Collections
--------------------
type Set<'T (requires comparison)> =
interface IReadOnlyCollection<'T>
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
...
--------------------
new : elements:seq<'T> -> Set<'T>
type NonEmptySetValidator<'T (requires comparison)> =
inherit Pi<unit,Set<'T>,Set<'T> option>
new : unit -> NonEmptySetValidator<'T>
--------------------
new : unit -> NonEmptySetValidator<'T>
from Tutorial
type NonEmptySetValidator<'T (requires comparison)> =
inherit Pi<unit,Set<'T>,Set<'T> option>
new : unit -> NonEmptySetValidator<'T>
--------------------
new : unit -> NonEmptySetDef.NonEmptySetValidator<'T>
type MinNumRangeValidator =
inherit Pi<int,int,int option>
new : config:int -> MinNumRangeValidator
--------------------
new : config:int -> MinNumRangeValidator
type MaxNumRangeValidator =
inherit Pi<int,int,int option>
new : config:int -> MaxNumRangeValidator
--------------------
new : config:int -> MaxNumRangeValidator
type MaxPos20000 =
inherit NumRangeValidator
new : unit -> MaxPos20000
--------------------
new : unit -> MaxPos20000
type RangeMinus100To100 =
inherit NumRangeValidator
new : unit -> RangeMinus100To100
--------------------
new : unit -> RangeMinus100To100
type Min101 =
inherit MinNumRangeValidator
new : unit -> Min101
--------------------
new : unit -> Min101
type MaxMinus101 =
inherit MaxNumRangeValidator
new : unit -> MaxMinus101
--------------------
new : unit -> MaxMinus101
from Tutorial
type MaxPos100 =
inherit NumRangeValidator
new : unit -> MaxPos100
--------------------
new : unit -> IntRange.MaxPos100
type MaxPos20000 =
inherit NumRangeValidator
new : unit -> MaxPos20000
--------------------
new : unit -> IntRange.MaxPos20000
type RangeMinus100To100 =
inherit NumRangeValidator
new : unit -> RangeMinus100To100
--------------------
new : unit -> IntRange.RangeMinus100To100
type Min101 =
inherit MinNumRangeValidator
new : unit -> Min101
--------------------
new : unit -> IntRange.Min101
type MaxMinus101 =
inherit MaxNumRangeValidator
new : unit -> MaxMinus101
--------------------
new : unit -> IntRange.MaxMinus101
type LenValidator =
inherit Pi<int,string,string option>
new : config:int -> LenValidator
--------------------
new : config:int -> LenValidator
type PairLenValidator =
inherit Sigma<int,string,string option>
new : config:int -> PairLenValidator
--------------------
new : config:int -> PairLenValidator
type Sigma<'Config,'T,'T2> =
new : config:'Config * pi:('Config -> 'T -> 'T2) -> Sigma<'Config,'T,'T2>
member Create : x:'T -> 'T * 'T2
--------------------
new : config:'Config * pi:('Config -> 'T -> 'T2) -> Sigma<'Config,'T,'T2>
type SizeMax5 =
inherit LenValidator
new : unit -> SizeMax5
--------------------
new : unit -> SizeMax5
type SizeMax5Pair =
inherit PairLenValidator
new : unit -> SizeMax5Pair
--------------------
new : unit -> SizeMax5Pair
union case DependentPair.DependentPair: 'T * 'T2 -> DependentPair<'Sigma,'Config,'T,'T2>
--------------------
type DependentPair<'Sigma,'Config,'T,'T2 (requires 'Sigma :> Sigma<'Config,'T,'T2> and default constructor)> =
| DependentPair of 'T * 'T2
member Value : 'T * 'T2
static member Create : x:'T -> DependentPair<'Sigma,'Config,'T,'T2>
from Tutorial
type SizeMax5Pair =
inherit PairLenValidator
new : unit -> SizeMax5Pair
--------------------
new : unit -> SizeMax5Type.SizeMax5Pair
| NonNegativeInt of int
| NegativeInt of int
type IntSumTypeDiscriminator =
inherit Pi<unit,IntegerOfSign,IntegerNegNonNeg>
new : unit -> IntSumTypeDiscriminator
--------------------
new : unit -> IntSumTypeDiscriminator
from Tutorial
type IntSumTypeDiscriminator =
inherit Pi<unit,IntegerOfSign,IntegerNegNonNeg>
new : unit -> IntSumTypeDiscriminator
--------------------
new : unit -> NonNegativSumType.IntSumTypeDiscriminator