An immutable range library in F# where a range is only defined by a minimum and a maximum value (hence, there is no step).
Source
type Range<'a when 'a:comparison> = { Min : 'a Max : 'a } override x.ToString() = sprintf "Range (%A, %A)" x.Min x.Max [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module Range = type t<'a when 'a:comparison> = Range<'a> let checkMinMax min max = if min > max then invalidArg "min" <| sprintf "min:%A > max:%A" min max let isValid r = r.Min <= r.Max let checkRange r = if not <| isValid r then invalidArg "r" <| sprintf "r.Min:%A > r.Max:%A" r.Min r.Max let create min max = checkMinMax min max { Min = min Max = max } let contains x r = checkRange r r.Min <= x && x <= r.Max let englobes r' r = checkRange r' checkRange r contains (r'.Min) r && contains (r'.Max) r let startsBefore x r = checkRange r r.Min < x let startsAfter x r = checkRange r r.Min > x let endsBefore x r = checkRange r r.Max < x let endsAfter x r = checkRange r r.Max > x let areAdjacent r r' = checkRange r' checkRange r r'.Min = r.Max || r.Min = r'.Max let doIntersect r r' = checkRange r' checkRange r contains (r'.Min) r || contains (r'.Max) r || englobes r r' let intersection r r' = checkRange r' checkRange r if doIntersect r r' then Some <| create (max (r.Min) (r'.Min)) (min (r.Max) (r'.Max)) else None let merge r r' = checkRange r' checkRange r if doIntersect r r' then Some <| create (min (r.Min) (r'.Min)) (max (r.Max) (r'.Max)) else None let inline length r = r.Max - r.Min
Signature
type Range<'a when 'a:comparison> = { Min : 'a Max : 'a } override ToString : unit -> string [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] module Range = type t<'a when 'a:comparison> = Range<'a> ///[create low high] returns a new [Range] initialized with [low] and [high] as its bounds. val create : low:'a -> high:'a -> Range<'a> ///[contains x r] returns true if [x] falls within the bounds of [r]. val contains : x:'a -> r:t<'a> -> bool ///[englobes r' r] returns true if [r'] is englobed by [r]. val englobes : r':t<'a> -> r:t<'a> -> bool ///[startsBefore x r] returns true if [r] starts before [x], i.e. [x > LowerBound r]. val startsBefore : x:'a -> r:t<'a> -> bool ///[startsAfter x r] returns true if [r] starts after [x], i.e. [x < LowerBound r]. val startsAfter : x:'a -> r:t<'a> -> bool ///[endsBefore x r] returns true if [r] ends before [x], i.e. [x > UpperBound r]. val endsBefore : x:'a -> r:t<'a> -> bool ///[endsAfter x r] returns true if [r] ends after [x], i.e. [x < UpperBound r]. val endsAfter : x:'a -> r:t<'a> -> bool ///[areAdjacent r r'] returns true if [r] and [r'] share a bound. val areAdjacent : r:t<'a> -> r':t<'a> -> bool ///[doIntersect r r'] returns true if [r] and [r'] cross over. val doIntersect : r:t<'a> -> r':t<'a> -> bool ///[intersection r r'] returns [None] if [r] and [r'] don't intersect ///[Some x] if they do intersect, where [x] is the [Range] ///where [r] and [r'] intersect. val intersection : r:t<'a> -> r':t<'a> -> option<t<'a>> ///[merge r r'] returns [None] if [r] and [r'] don't intersect ///[Some x] if they do intersect, where [x] is the [Range] ///with the lowest bound and uppest bound of [r] and [r']. val merge : r:t<'a> -> r':t<'a> -> option<t<'a>> ///[length r] returns the difference between the upper and lower bounds of [r]. val inline length : t< ^a> -> ^b when ^a : (static member ( - ) : ^a * ^a -> ^b)