4 people like it.
Like the snippet!
Emulating higher level typing using inline functions and member constraints
This pattern shows that by using a few static member constraints, one can create an assortment of data processing functions that emulate higher level typing than is possible in F#.
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:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
|
let inline iter (f : 'a -> unit) (x : 's) = (^s : (member Iter : ('a -> unit) -> unit) x,f)
let inline iterBack (f : 'a -> unit) (x : 's) = (^s : (member IterBack : ('a -> unit) -> unit) x,f)
let inline empty () = (^s : (static member Empty : 's) ())
let inline (+>) item col = (^s : (member AddFirst : 'a -> 's) col,item)
let inline (<+) col item = (^s : (member AddLast : 'a -> 's) col,item)
let inline (<+>) col1 col2 = (^s : (static member Concat : 's -> 's -> 's) col1,col2)
let inline (++>) items col = (^s : (member AddManyFirst : #seq<_> -> 's) col,items)
let inline (<++) col items = (^s : (member AddManyLast : #seq<_> -> 's) col,items)
//++ Advanced Operators
//The following operators deal with adding or removing items from a data structure.
///Returns the first elements of the data structure
let inline takef n col = (^s : (member TakeFirst : int -> ^s) col,n)
///Returns the last elements of the data structure
let inline takel n col = (^s : (member TakeLast : int -> ^s) col,n)
///Splits the data structure at the specified index.
let inline split n col = (^s : (member Split : int -> ^s * ^s) col,n)
///Gets the first element of the data structure
let inline first col = (^s : (member First : 'a) col)
///Gets the last element of the data structure
let inline last col = (^s : (member Last : 'a) col)
///Gets the element with the specified index from the data structure
let inline get i col = (^s : (member Item : int -> ^a) col,i)
///Sets the element with the specified index from the data structure
let inline set i v col = (^s : (member Set : ^k * 'a -> 's) col,i,v)
///Removes the first element from the data structure.
let inline dropf col = (^s : (member DropFirst : ^s) col)
///Removes the last element from the data structure.
let inline dropl col = (^s : (member DropLast : ^s) col)
let inline fromSeq (sq : #seq<_>) = (^s : (static member FromSeq : seq<'a> -> 's) sq)
///Reverses the data structure.
let inline reverse col = (^s : (member Reverse : ^s) col)
///Gets the length of the data structure.
let inline length col = (^s : (member Length : int) col)
//++ Derived Operators
// These operators use the above operators to apply functions on data structure, filter, etc.
let inline splice index inner outer =
let part1,part2 = outer |> split index
let part1 = part1 <+> inner
let closed = part1 <+> part2
closed
let inline droplMany n target =
let len = target |> length
let first = target |> takef (len - n)
first
let inline dropfMany n target =
let len = target |> length
let last = target |> takel (len - n)
last
let inline insertManyAt index (sq : seq<'a>) (target : ^s) =
let ins = (sq |> fromSeq)
target |> splice index ins
let inline removeAt index target =
let part1,part2 = target |> split index
let part1 = part1 |> dropl
part1 <+> part2
let inline removeManyAt index count target=
let part1,part2 = target |> split index
let part1 = part1 |> droplMany count
part1 <+> part2
let inline insertAt index item target =
let part1,part2 = target |> split index
let part1 = part1 <+ item
let closed = part1 <+> part2
closed
///Applies the specified transformation on the data structure.
let inline map (f : 'a -> 'b) col =
let refRoot = ref (empty() : 'b)
let mapIter x =
let x = x |> f
refRoot := (!refRoot <+ x)
col |> iter mapIter
!refRoot
///Filters the data structure using the specified predicate.
let inline filter (f : 'a -> bool) (col : 's) : 's =
let refRoot = ref (empty() : ^s)
let filterIter (x : 'a) =
if f x then refRoot := !refRoot <+ x
col |> iter filterIter
!refRoot
///Applies a a function on the data structure, keeping all elements which return Some, and dropping all those that return None.
let inline choose (f : _ -> _ option) col =
let refRoot = ref (empty() : 'b)
let chooseIter x =
match f x with
| None -> ()
| Some y -> refRoot := !refRoot + y
col |> iter chooseIter
!refRoot
///Constructs a linked list from the elements of this data structure
let inline toList col =
let refList = ref []
let listIter x =
refList := x :: !refList
col |> iter listIter
!refList
///Folds over the data structure using the specified function.
let inline fold (foldr : _-> _ -> _) (start : _) col =
let refState = ref start
let foldIter x =
refState := foldr (refState.Value) x
col |> iter foldIter
!refState
///Folds over the data structure backwards, using the specified function.
let inline foldBack (foldr :_ -> _ -> _) (start :_) col =
let refState = ref start
let foldbIter x =
refState := foldr (refState.Value) x
col |> iterBack foldbIter
!refState
///Returns true if the specified predicate is true for all items in the data structure.
let inline forall (pred : _ -> bool) col =
col |> fold (fun cur item -> cur && pred(item)) true
///Returns true if the specified predicate is true for any item in the data structure.
let inline forany (pred : _ -> bool) col =
col |> fold (fun cur item -> cur || pred(item)) false
///Counts the number of items for which the specified predicate is true.
let inline count (pred : _ -> bool) col =
col |> fold (fun cur item -> if pred(item) then cur + 1 else cur) 0
let inline toArray col =
let l = col |> length
let arr = Array.zeroCreate l
for i,item in Seq.zip {0 .. l} col do
arr.[i] <- item
arr
|
val iter : f:('a -> unit) -> x:'s -> unit (requires member Iter)
Full name: Script.iter
val f : ('a -> unit)
type unit = Unit
Full name: Microsoft.FSharp.Core.unit
val x : 's (requires member Iter)
val iterBack : f:('a -> unit) -> x:'s -> unit (requires member IterBack)
Full name: Script.iterBack
val x : 's (requires member IterBack)
val empty : unit -> 's (requires member get_Empty)
Full name: Script.empty
val item : 'a
val col : 's (requires member AddFirst)
val col : 's (requires member AddLast)
val col1 : 's (requires member Concat)
val col2 : 's (requires member Concat)
val items : #seq<'b>
val col : 's (requires member AddManyFirst and 'a :> seq<'b>)
Multiple items
val seq : sequence:seq<'T> -> seq<'T>
Full name: Microsoft.FSharp.Core.Operators.seq
--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>
Full name: Microsoft.FSharp.Collections.seq<_>
val col : 's (requires member AddManyLast and 'a :> seq<'b>)
val takef : n:int -> col:'s -> 's (requires member TakeFirst)
Full name: Script.takef
Returns the first elements of the data structure
val n : int
val col : 's (requires member TakeFirst)
Multiple items
val int : value:'T -> int (requires member op_Explicit)
Full name: Microsoft.FSharp.Core.Operators.int
--------------------
type int = int32
Full name: Microsoft.FSharp.Core.int
--------------------
type int<'Measure> = int
Full name: Microsoft.FSharp.Core.int<_>
val takel : n:int -> col:'s -> 's (requires member TakeLast)
Full name: Script.takel
Returns the last elements of the data structure
val col : 's (requires member TakeLast)
val split : n:int -> col:'s -> 's * 's (requires member Split)
Full name: Script.split
Splits the data structure at the specified index.
val col : 's (requires member Split)
val first : col:'s -> 'a (requires member get_First)
Full name: Script.first
Gets the first element of the data structure
val col : 's (requires member get_First)
val last : col:'s -> 'a (requires member get_Last)
Full name: Script.last
Gets the last element of the data structure
val col : 's (requires member get_Last)
val get : i:int -> col:'s -> 'a (requires member Item)
Full name: Script.get
Gets the element with the specified index from the data structure
val i : int
val col : 's (requires member Item)
val set : i:'k -> v:'a -> col:'s -> 's (requires member Set)
Full name: Script.set
Sets the element with the specified index from the data structure
val i : 'k
val v : 'a
val col : 's (requires member Set)
Multiple items
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
...
Full name: Microsoft.FSharp.Collections.Set<_>
--------------------
new : elements:seq<'T> -> Set<'T>
val dropf : col:'s -> 's (requires member get_DropFirst)
Full name: Script.dropf
Removes the first element from the data structure.
val col : 's (requires member get_DropFirst)
val dropl : col:'s -> 's (requires member get_DropLast)
Full name: Script.dropl
Removes the last element from the data structure.
val col : 's (requires member get_DropLast)
val fromSeq : sq:#seq<'a0> -> 's (requires member FromSeq)
Full name: Script.fromSeq
val sq : #seq<'a0>
val reverse : col:'s -> 's (requires member get_Reverse)
Full name: Script.reverse
Reverses the data structure.
val col : 's (requires member get_Reverse)
val length : col:'s -> int (requires member get_Length)
Full name: Script.length
Gets the length of the data structure.
val col : 's (requires member get_Length)
val splice : index:int -> inner:'a -> outer:'a -> 'a (requires member Concat and member Split)
Full name: Script.splice
val index : int
val inner : 'a (requires member Concat and member Split)
val outer : 'a (requires member Concat and member Split)
val part1 : 'a (requires member Concat and member Split)
val part2 : 'a (requires member Concat and member Split)
val closed : 'a (requires member Concat and member Split)
val droplMany : n:int -> target:'a -> 'a (requires member TakeFirst and member get_Length)
Full name: Script.droplMany
val target : 'a (requires member TakeFirst and member get_Length)
val len : int
val first : 'a (requires member TakeFirst and member get_Length)
val dropfMany : n:int -> target:'a -> 'a (requires member TakeLast and member get_Length)
Full name: Script.dropfMany
val target : 'a (requires member TakeLast and member get_Length)
val last : 'a (requires member TakeLast and member get_Length)
val insertManyAt : index:int -> sq:seq<'a> -> target:'s -> 's (requires member Concat and member Split and member FromSeq)
Full name: Script.insertManyAt
val sq : seq<'a>
val target : 's (requires member Concat and member Split and member FromSeq)
val ins : 's (requires member Concat and member Split and member FromSeq)
val removeAt : index:int -> target:'a -> 'a (requires member get_DropLast and member Split and member Concat)
Full name: Script.removeAt
val target : 'a (requires member get_DropLast and member Split and member Concat)
val part1 : 'a (requires member get_DropLast and member Split and member Concat)
val part2 : 'a (requires member get_DropLast and member Split and member Concat)
val removeManyAt : index:int -> count:int -> target:'a -> 'a (requires member TakeFirst and member get_Length and member Split and member Concat)
Full name: Script.removeManyAt
val count : int
val target : 'a (requires member TakeFirst and member get_Length and member Split and member Concat)
val part1 : 'a (requires member TakeFirst and member get_Length and member Split and member Concat)
val part2 : 'a (requires member TakeFirst and member get_Length and member Split and member Concat)
val insertAt : index:int -> item:'a -> target:'b -> 'b (requires member Split and member AddLast and member Concat)
Full name: Script.insertAt
val target : 'b (requires member Split and member AddLast and member Concat)
val part1 : 'b (requires member Split and member AddLast and member Concat)
val part2 : 'b (requires member Split and member AddLast and member Concat)
val closed : 'b (requires member Split and member AddLast and member Concat)
val map : f:('a -> 'b) -> col:'a0 -> 'b (requires member get_Empty and member AddLast and member Iter)
Full name: Script.map
Applies the specified transformation on the data structure.
val f : ('a -> 'b) (requires member get_Empty and member AddLast)
val col : 'a (requires member Iter)
val refRoot : 'b ref (requires member get_Empty and member AddLast)
Multiple items
val ref : value:'T -> 'T ref
Full name: Microsoft.FSharp.Core.Operators.ref
--------------------
type 'T ref = Ref<'T>
Full name: Microsoft.FSharp.Core.ref<_>
val mapIter : ('a -> unit)
val x : 'a
val x : 'b (requires member get_Empty and member AddLast)
val filter : f:('a -> bool) -> col:'s -> 's (requires member get_Empty and member AddLast and member Iter)
Full name: Script.filter
Filters the data structure using the specified predicate.
val f : ('a -> bool)
type bool = System.Boolean
Full name: Microsoft.FSharp.Core.bool
val col : 's (requires member get_Empty and member AddLast and member Iter)
val refRoot : 's ref (requires member get_Empty and member AddLast and member Iter)
val filterIter : ('a -> unit)
val choose : f:('a -> 'b option) -> col:'c -> 'b0 (requires member ( + ) and member get_Empty and member Iter)
Full name: Script.choose
Applies a a function on the data structure, keeping all elements which return Some, and dropping all those that return None.
val f : ('a -> 'b option) (requires member ( + ) and member get_Empty)
type 'T option = Option<'T>
Full name: Microsoft.FSharp.Core.option<_>
val col : 'c (requires member Iter)
val refRoot : 'b ref (requires member get_Empty and member ( + ))
val chooseIter : ('a -> unit)
union case Option.None: Option<'T>
union case Option.Some: Value: 'T -> Option<'T>
val y : 'b (requires member ( + ) and member get_Empty)
val toList : col:'a -> 'b list (requires member Iter)
Full name: Script.toList
Constructs a linked list from the elements of this data structure
val refList : 'b list ref
val listIter : ('b -> unit)
val x : 'b
val fold : foldr:('a -> 'b -> 'a) -> start:'a -> col:'c -> 'a (requires member Iter)
Full name: Script.fold
Folds over the data structure using the specified function.
val foldr : ('a -> 'b -> 'a)
val start : 'a
val refState : 'a ref
val foldIter : ('b -> unit)
property Ref.Value: 'a
val foldBack : foldr:('a -> 'b -> 'a) -> start:'a -> col:'c -> 'a (requires member IterBack)
Full name: Script.foldBack
Folds over the data structure backwards, using the specified function.
val col : 'c (requires member IterBack)
val foldbIter : ('b -> unit)
val forall : pred:('a -> bool) -> col:'b -> bool (requires member Iter)
Full name: Script.forall
Returns true if the specified predicate is true for all items in the data structure.
val pred : ('a -> bool)
val col : 'b (requires member Iter)
val cur : bool
val forany : pred:('a -> bool) -> col:'b -> bool (requires member Iter)
Full name: Script.forany
Returns true if the specified predicate is true for any item in the data structure.
val count : pred:('a -> bool) -> col:'b -> int (requires member Iter)
Full name: Script.count
Counts the number of items for which the specified predicate is true.
val cur : int
val toArray : col:'a -> 'b [] (requires member get_Length and 'a :> seq<'b>)
Full name: Script.toArray
val col : 'a (requires member get_Length and 'a :> seq<'b>)
val l : int
val arr : 'b []
module Array
from Microsoft.FSharp.Collections
val zeroCreate : count:int -> 'T []
Full name: Microsoft.FSharp.Collections.Array.zeroCreate
val item : 'b
module Seq
from Microsoft.FSharp.Collections
val zip : source1:seq<'T1> -> source2:seq<'T2> -> seq<'T1 * 'T2>
Full name: Microsoft.FSharp.Collections.Seq.zip
More information