Skip to content

Commit db6fbe2

Browse files
committed
Updated List type
1 parent e0eada6 commit db6fbe2

File tree

4 files changed

+150
-84
lines changed

4 files changed

+150
-84
lines changed

src/Fable.Transforms/Fable2Babel.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ module Reflection =
283283
| Fable.Array _ | Fable.Tuple _ ->
284284
libCall com ctx None "Util" "isArrayLike" [|com.TransformAsExpr(ctx, expr)|]
285285
| Fable.List _ ->
286-
jsInstanceof (libValue com ctx "Types" "List") expr
286+
jsInstanceof (libValue com ctx "List" "List$1") expr
287287
| Fable.AnonymousRecordType _ ->
288288
warnAndEvalToFalse "anonymous records"
289289
| Fable.MetaType ->

src/fable-library/List.fs

Lines changed: 133 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module List
1+
module LinkedList
22

33
open Fable.Core
44

@@ -16,18 +16,26 @@ module SR =
1616
[<CustomEquality; CustomComparison>]
1717
// [<CompiledName("FSharpList`1")>]
1818
type List<'T when 'T: comparison> =
19-
{ head: 'T; tail: List<'T> option }
19+
{ head: 'T; mutable tail: List<'T> option }
2020

2121
static member inline Empty: List<'T> = { head = Unchecked.defaultof<'T>; tail = None }
2222
static member inline Cons (x: 'T, xs: 'T list) = { head = x; tail = Some xs }
2323

24-
member xs.IsEmpty = xs.tail.IsNone
24+
static member inline internal ConsNoTail (x: 'T) = { head = x; tail = None }
25+
member inline internal xs.SetConsTail (t: 'T list) = xs.tail <- Some t
26+
member inline internal xs.AppendConsNoTail (x: 'T) =
27+
let t = List.ConsNoTail x
28+
xs.SetConsTail t
29+
t
30+
31+
member inline xs.IsEmpty = xs.tail.IsNone
2532

2633
member xs.Length =
27-
let rec loop i = function
34+
let rec loop i xs =
35+
match xs.tail with
2836
| None -> i
29-
| Some t -> loop (i + 1) t.tail
30-
loop 0 xs.tail
37+
| Some t -> loop (i + 1) t
38+
loop 0 xs
3139

3240
member xs.Head =
3341
match xs.tail with
@@ -56,20 +64,40 @@ type List<'T when 'T: comparison> =
5664
then true
5765
else
5866
let ys = other :?> 'T list
59-
Seq.forall2 (Unchecked.equals) xs ys
67+
let rec loop xs ys =
68+
match xs.tail, ys.tail with
69+
| None, None -> true
70+
| None, Some _ -> false
71+
| Some _, None -> false
72+
| Some xt, Some yt ->
73+
if xs.head = ys.head
74+
then loop xt yt
75+
else false
76+
loop xs ys
6077

6178
override xs.GetHashCode() =
6279
let inline combineHash i x y = (x <<< 1) + y + 631 * i
63-
let mutable i = 0
64-
let mutable h = 0
65-
for x in xs do
66-
i <- i + 1
67-
h <- combineHash i h (hash x)
68-
h
80+
let iMax = 18 // limit the hash
81+
let rec loop i h (xs: 'T list) =
82+
match xs.tail with
83+
| None -> h
84+
| Some t ->
85+
if i > iMax then h
86+
else loop (i + 1) (combineHash i h (hash xs.head)) t
87+
loop 0 0 xs
6988

7089
interface System.IComparable with
7190
member xs.CompareTo(other: obj) =
72-
Seq.compareWith compare xs (other :?> 'T list)
91+
let ys = other :?> 'T list
92+
let rec loop xs ys =
93+
match xs.tail, ys.tail with
94+
| None, None -> 0
95+
| None, Some _ -> -1
96+
| Some _, None -> 1
97+
| Some xt, Some yt ->
98+
let c = compare xs.head ys.head
99+
if c = 0 then loop xt yt else c
100+
loop xs ys
73101

74102
interface System.Collections.Generic.IEnumerable<'T> with
75103
member xs.GetEnumerator(): System.Collections.Generic.IEnumerator<'T> =
@@ -138,70 +166,110 @@ let last (xs: 'T list) =
138166
| None -> failwith SR.inputListWasEmpty
139167

140168
let compareWith (comparer: 'T -> 'T -> int) (xs: 'T list) (ys: 'T list): int =
141-
Seq.compareWith comparer xs ys
142-
143-
let fold (folder: 'acc -> 'T -> 'acc) (state: 'acc) (xs: 'T list) =
169+
let rec loop (xs: 'T list) (ys: 'T list) =
170+
match xs.IsEmpty, ys.IsEmpty with
171+
| true, true -> 0
172+
| true, false -> -1
173+
| false, true -> 1
174+
| false, false ->
175+
let c = comparer xs.Head ys.Head
176+
if c = 0 then loop xs.Tail ys.Tail else c
177+
loop xs ys
178+
179+
let fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
144180
let rec loop acc (ys: 'T list) =
145181
if ys.IsEmpty then acc
146182
else loop (folder acc ys.Head) ys.Tail
147183
loop state xs
148184

149-
let foldBack (folder: 'T -> 'acc -> 'acc) (xs: 'T list) (state: 'acc) =
185+
let foldBack (folder: 'T -> 'State -> 'State) (xs: 'T list) (state: 'State) =
150186
Seq.foldBack folder xs state
151187

152-
let foldIndexed (folder: int -> 'acc -> 'T -> 'acc) (state: 'acc) (xs: 'T list) =
188+
let foldIndexed (folder: int -> 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
153189
let rec loop i acc (ys: 'T list) =
154190
if ys.IsEmpty then acc
155191
else loop (i + 1) (folder i acc ys.Head) ys.Tail
156192
loop 0 state xs
157193

158-
let reverse (xs: 'a list) =
194+
let reverse (xs: 'T list) =
159195
fold (fun acc x -> List.Cons(x, acc)) List.Empty xs
160196

161-
let toSeq (xs: 'a list): 'a seq =
162-
xs :> System.Collections.Generic.IEnumerable<'a>
197+
let toSeq (xs: 'T list): 'T seq =
198+
xs :> System.Collections.Generic.IEnumerable<'T>
163199

164-
let ofSeq (xs: 'a seq): 'a list =
165-
Seq.fold (fun acc x -> List.Cons(x, acc)) List.Empty xs
166-
|> reverse
200+
let ofArrayWithTail (xs: System.Collections.Generic.IList<'T>) (tail: 'T list) =
201+
let mutable res = tail
202+
for i = xs.Count - 1 downto 0 do
203+
res <- List.Cons(xs.[i], res)
204+
res
167205

168-
let concat (lists: seq<'a list>) =
206+
let ofArray (xs: System.Collections.Generic.IList<'T>) =
207+
ofArrayWithTail xs List.Empty
208+
209+
let ofSeq (xs: seq<'T>): 'T list =
210+
match xs with
211+
| :? list<'T> as lst -> lst
212+
| :? array<'T> as arr -> ofArray arr
213+
| _ ->
214+
let root = List.Empty
215+
let mutable node = root
216+
for x in xs do
217+
node <- node.AppendConsNoTail x
218+
node.SetConsTail List.Empty
219+
root.Tail
220+
221+
let concat (lists: seq<'T list>) =
169222
Seq.fold (fold (fun acc x -> List.Cons(x, acc))) List.Empty lists
170223
|> reverse
171224

172-
let fold2 f (state: 'acc) (xs: 'a list) (ys: 'b list) =
225+
let fold2 f (state: 'State) (xs: 'T list) (ys: 'U list) =
173226
Seq.fold2 f state xs ys
174227

175-
let foldBack2 f (xs: 'a list) (ys: 'b list) (state: 'acc) =
228+
let foldBack2 f (xs: 'T list) (ys: 'U list) (state: 'State) =
176229
Seq.foldBack2 f xs ys state
177230

178-
let unfold (gen: 'acc -> ('T * 'acc) option) (state: 'acc) =
179-
let rec loop st acc =
231+
let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
232+
let rec loop st (node: 'T list) =
180233
match gen st with
181-
| None -> reverse acc
182-
| Some (x, st) -> loop st (List.Cons(x, acc))
183-
loop state List.Empty
234+
| None -> node.SetConsTail List.Empty
235+
| Some (x, st) -> loop st (node.AppendConsNoTail x)
236+
let root = List.Empty
237+
loop state root
238+
root.Tail
184239

185-
let scan f (state: 'acc) (xs: 'a list) =
240+
let scan f (state: 'State) (xs: 'T list) =
186241
Seq.scan f state xs |> ofSeq
187242

188-
let scanBack f (xs: 'a list) (state: 'acc) =
243+
let scanBack f (xs: 'T list) (state: 'State) =
189244
Seq.scanBack f xs state |> ofSeq
190245

191-
let append (xs: 'a list) (ys: 'a list) =
246+
let append (xs: 'T list) (ys: 'T list) =
192247
fold (fun acc x -> List.Cons(x, acc)) ys (reverse xs)
193248

194-
let collect (f: 'a -> 'b list) (xs: 'a list) =
195-
Seq.collect f xs |> ofSeq
196-
197-
let mapIndexed (f: int -> 'a -> 'b) (xs: 'a list) =
198-
foldIndexed (fun i acc x -> List.Cons(f i x, acc)) List.Empty xs
199-
|> reverse
200-
201-
let map (f: 'a -> 'b) (xs: 'a list) =
249+
let collect (f: 'T -> 'U list) (xs: 'T list) =
250+
let root = List.Empty
251+
let mutable node = root
252+
let mutable ys = xs
253+
while not ys.IsEmpty do
254+
let mutable zs = f ys.Head
255+
while not zs.IsEmpty do
256+
node <- node.AppendConsNoTail zs.Head
257+
zs <- zs.Tail
258+
ys <- ys.Tail
259+
node.SetConsTail List.Empty
260+
root.Tail
261+
262+
let mapIndexed (f: int -> 'T -> 'U) (xs: 'T list) =
263+
let root = List.Empty
264+
let folder i (acc: 'U list) x = acc.AppendConsNoTail (f i x)
265+
let node = foldIndexed folder root xs
266+
node.SetConsTail List.Empty
267+
root.Tail
268+
269+
let map (f: 'T -> 'U) (xs: 'T list) =
202270
mapIndexed (fun i x -> f x) xs
203271

204-
let indexed (xs: 'a list) =
272+
let indexed xs =
205273
mapIndexed (fun i x -> (i, x)) xs
206274

207275
let map2 f xs ys =
@@ -235,26 +303,17 @@ let iterateIndexed f xs =
235303
let iterateIndexed2 f xs ys =
236304
fold2 (fun i x y -> f i x y; i + 1) 0 xs ys |> ignore
237305

238-
let ofArrayWithTail (xs: System.Collections.Generic.IList<'T>) (tail: 'T list) =
239-
let mutable res = tail
240-
for i = xs.Count - 1 downto 0 do
241-
res <- List.Cons(xs.[i], res)
242-
res
243-
244-
let ofArray (xs: System.Collections.Generic.IList<'T>) =
245-
ofArrayWithTail xs List.Empty
246-
247-
let tryPickIndexed (f: int -> 'a -> 'b option) (xs: 'a list) =
248-
let rec loop i (ys: 'a list) =
306+
let tryPickIndexed (f: int -> 'T -> 'U option) (xs: 'T list) =
307+
let rec loop i (ys: 'T list) =
249308
if ys.IsEmpty then None
250309
else
251310
match f i ys.Head with
252311
| Some _ as res -> res
253312
| None -> loop (i + 1) ys.Tail
254313
loop 0 xs
255314

256-
let tryPickIndexedBack (f: int -> 'a -> 'b option) (xs: 'a list) =
257-
let rec loop i acc (ys: 'a list) =
315+
let tryPickIndexedBack (f: int -> 'T -> 'U option) (xs: 'T list) =
316+
let rec loop i acc (ys: 'T list) =
258317
if ys.IsEmpty then acc
259318
else
260319
let result =
@@ -316,15 +375,15 @@ let findIndexBack f xs: int =
316375
| None -> indexNotFound()
317376
| Some x -> x
318377

319-
let tryItem n (xs: 'a list) =
320-
let rec loop i (ys: 'a list) =
378+
let tryItem n (xs: 'T list) =
379+
let rec loop i (ys: 'T list) =
321380
if ys.IsEmpty then None
322381
else
323382
if i = n then Some ys.Head
324383
else loop (i + 1) ys.Tail
325384
loop 0 xs
326385

327-
let item n (xs: 'a list) = xs.Item(n)
386+
let item n (xs: 'T list) = xs.Item(n)
328387

329388
let filter f xs =
330389
fold (fun acc x ->
@@ -348,8 +407,8 @@ let choose f xs =
348407
let contains (value: 'T) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'T>) =
349408
tryFindIndex (fun v -> eq.Equals (value, v)) xs |> Option.isSome
350409

351-
let except (itemsToExclude: seq<'t>) (xs: 't list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'t>): 't list =
352-
if isEmpty xs then xs
410+
let except (itemsToExclude: seq<'T>) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'T>) =
411+
if xs.IsEmpty then xs
353412
else
354413
let cached = System.Collections.Generic.HashSet(itemsToExclude, eq)
355414
xs |> filter cached.Add
@@ -363,12 +422,12 @@ let initialize n f =
363422
let replicate n x =
364423
initialize n (fun _ -> x)
365424

366-
let reduce f xs =
367-
if isEmpty xs then invalidOp SR.inputListWasEmpty
425+
let reduce f (xs: 'T list) =
426+
if xs.IsEmpty then invalidOp SR.inputListWasEmpty
368427
else fold f (head xs) (tail xs)
369428

370-
let reduceBack f xs =
371-
if isEmpty xs then invalidOp SR.inputListWasEmpty
429+
let reduceBack f (xs: 'T list) =
430+
if xs.IsEmpty then invalidOp SR.inputListWasEmpty
372431
else foldBack f (tail xs) (head xs)
373432

374433
let forAll f xs =
@@ -380,7 +439,7 @@ let forAll2 f xs ys =
380439
let exists f xs =
381440
tryFindIndex f xs |> Option.isSome
382441

383-
let rec exists2 f (xs: 'a list) (ys: 'b list) =
442+
let rec exists2 f (xs: 'T list) (ys: 'U list) =
384443
match xs.IsEmpty, ys.IsEmpty with
385444
| true, true -> false
386445
| false, false -> f xs.Head ys.Head || exists2 f xs.Tail ys.Tail
@@ -406,28 +465,28 @@ let sortWith (comparison: 'T -> 'T -> int) (xs: 'T list): 'T list =
406465
let sort (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T list =
407466
sortWith (fun x y -> comparer.Compare(x, y)) xs
408467

409-
let sortBy (projection: 'a -> 'b) (xs: 'a list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'b>): 'a list =
468+
let sortBy (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T list =
410469
sortWith (fun x y -> comparer.Compare(projection x, projection y)) xs
411470

412471
let sortDescending (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T list =
413472
sortWith (fun x y -> comparer.Compare(x, y) * -1) xs
414473

415-
let sortByDescending (projection: 'a -> 'b) (xs: 'a list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'b>): 'a list =
474+
let sortByDescending (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T list =
416475
sortWith (fun x y -> comparer.Compare(projection x, projection y) * -1) xs
417476

418477
let sum (xs: 'T list) ([<Inject>] adder: IGenericAdder<'T>): 'T =
419478
fold (fun acc x -> adder.Add(acc, x)) (adder.GetZero()) xs
420479

421-
let sumBy (f: 'T -> 'T2) (xs: 'T list) ([<Inject>] adder: IGenericAdder<'T2>): 'T2 =
480+
let sumBy (f: 'T -> 'U) (xs: 'T list) ([<Inject>] adder: IGenericAdder<'U>): 'U =
422481
fold (fun acc x -> adder.Add(acc, f x)) (adder.GetZero()) xs
423482

424-
let maxBy (projection: 'a -> 'b) xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'b>): 'a =
483+
let maxBy (projection: 'T -> 'U) xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T =
425484
reduce (fun x y -> if comparer.Compare(projection y, projection x) > 0 then y else x) xs
426485

427-
let max xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'a>): 'a =
486+
let max xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T =
428487
reduce (fun x y -> if comparer.Compare(y, x) > 0 then y else x) xs
429488

430-
let minBy (projection: 'a -> 'b) xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'b>): 'a =
489+
let minBy (projection: 'T -> 'U) xs ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T =
431490
reduce (fun x y -> if comparer.Compare(projection y, projection x) > 0 then x else y) xs
432491

433492
let min (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T =

src/fable-library/Map.fs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -426,10 +426,10 @@ module MapTree =
426426
res <- add comparer x y res
427427
res
428428

429-
let ofSeq comparer (c: seq<'Key * 'T>) =
429+
let ofSeq comparer (c: seq<'Key * 'Value>) =
430430
match c with
431-
| :? array<'Key * 'T> as xs -> ofArray comparer xs
432-
// | :? list<'Key * 'T> as xs -> ofList comparer xs
431+
| :? array<'Key * 'Value> as xs -> ofArray comparer xs
432+
| :? list<'Key * 'Value> as xs -> ofList comparer xs
433433
| _ ->
434434
use ie = c.GetEnumerator()
435435
mkFromEnumerator comparer empty ie
@@ -859,8 +859,8 @@ let ofSeq elements =
859859

860860
// [<CompiledName("OfArray")>]
861861
let ofArray (elements: ('Key * 'Value) array) =
862-
let comparer = LanguagePrimitives.FastGenericComparer<'Key>
863-
new Map<_, _>(comparer, MapTree.ofArray comparer elements)
862+
let comparer = LanguagePrimitives.FastGenericComparer<'Key>
863+
new Map<_, _>(comparer, MapTree.ofArray comparer elements)
864864

865865
// [<CompiledName("ToList")>]
866866
let toList (table: Map<_, _>) =

0 commit comments

Comments
 (0)