Skip to content

Commit f895a62

Browse files
committed
List type updates
1 parent db6fbe2 commit f895a62

File tree

5 files changed

+167
-97
lines changed

5 files changed

+167
-97
lines changed

src/Fable.Transforms/Replacements.fs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1906,7 +1906,6 @@ let listModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Exp
19061906
// Use a cast to give it better chances of optimization (e.g. converting list
19071907
// literals to arrays) after the beta reduction pass
19081908
| "ToSeq", [x] -> toSeq t x |> Some
1909-
| "ToArray", [x] -> toArray r t x |> Some
19101909
| "AllPairs", args ->
19111910
let allPairs = Helper.LibCall(com, "Seq", "allPairs", t, args, i.SignatureArgTypes, ?loc=r)
19121911
toList com t allPairs |> Some

src/fable-library/Array.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
module Array
1+
module ArrayModule
22

33
// Disables warn:1204 raised by use of LanguagePrimitives.ErrorStrings.*
44
#nowarn "1204"

src/fable-library/List.fs

Lines changed: 155 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ module SR =
1818
type List<'T when 'T: comparison> =
1919
{ head: 'T; mutable tail: List<'T> option }
2020

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

2424
static member inline internal ConsNoTail (x: 'T) = { head = x; tail = None }
@@ -176,34 +176,47 @@ let compareWith (comparer: 'T -> 'T -> int) (xs: 'T list) (ys: 'T list): int =
176176
if c = 0 then loop xs.Tail ys.Tail else c
177177
loop xs ys
178178

179+
let toArray (xs: 'T list) =
180+
let len = xs.Length
181+
let res = Array.zeroCreate len
182+
let rec loop i (xs: 'T list) =
183+
if not xs.IsEmpty then
184+
res.[i] <- xs.Head
185+
loop (i + 1) xs.Tail
186+
loop 0 xs
187+
res
188+
179189
let fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
180-
let rec loop acc (ys: 'T list) =
181-
if ys.IsEmpty then acc
182-
else loop (folder acc ys.Head) ys.Tail
183-
loop state xs
190+
let mutable acc = state
191+
let mutable xs = xs
192+
while not xs.IsEmpty do
193+
acc <- folder acc xs.Head
194+
xs <- xs.Tail
195+
acc
196+
197+
let reverse (xs: 'T list) =
198+
fold (fun acc x -> List.Cons(x, acc)) List.Empty xs
184199

185200
let foldBack (folder: 'T -> 'State -> 'State) (xs: 'T list) (state: 'State) =
186-
Seq.foldBack folder xs state
201+
// fold (fun acc x -> folder x acc) state (reverse xs)
202+
Array.foldBack folder (toArray xs) state
187203

188204
let foldIndexed (folder: int -> 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
189-
let rec loop i acc (ys: 'T list) =
190-
if ys.IsEmpty then acc
191-
else loop (i + 1) (folder i acc ys.Head) ys.Tail
205+
let rec loop i acc (xs: 'T list) =
206+
if xs.IsEmpty then acc
207+
else loop (i + 1) (folder i acc xs.Head) xs.Tail
192208
loop 0 state xs
193209

194-
let reverse (xs: 'T list) =
195-
fold (fun acc x -> List.Cons(x, acc)) List.Empty xs
196-
197210
let toSeq (xs: 'T list): 'T seq =
198211
xs :> System.Collections.Generic.IEnumerable<'T>
199212

200-
let ofArrayWithTail (xs: System.Collections.Generic.IList<'T>) (tail: 'T list) =
213+
let ofArrayWithTail (xs: 'T[]) (tail: 'T list) =
201214
let mutable res = tail
202-
for i = xs.Count - 1 downto 0 do
215+
for i = xs.Length - 1 downto 0 do
203216
res <- List.Cons(xs.[i], res)
204217
res
205218

206-
let ofArray (xs: System.Collections.Generic.IList<'T>) =
219+
let ofArray (xs: 'T[]) =
207220
ofArrayWithTail xs List.Empty
208221

209222
let ofSeq (xs: seq<'T>): 'T list =
@@ -212,21 +225,31 @@ let ofSeq (xs: seq<'T>): 'T list =
212225
| :? array<'T> as arr -> ofArray arr
213226
| _ ->
214227
let root = List.Empty
215-
let mutable node = root
216-
for x in xs do
217-
node <- node.AppendConsNoTail x
228+
let node = Seq.fold (fun (acc: 'T list) x -> acc.AppendConsNoTail x) root xs
218229
node.SetConsTail List.Empty
219230
root.Tail
220231

221232
let concat (lists: seq<'T list>) =
222-
Seq.fold (fold (fun acc x -> List.Cons(x, acc))) List.Empty lists
223-
|> reverse
233+
let root = List.Empty
234+
let mutable node = root
235+
for xs in lists do
236+
node <- fold (fun acc x -> acc.AppendConsNoTail x) node xs
237+
node.SetConsTail List.Empty
238+
root.Tail
224239

225-
let fold2 f (state: 'State) (xs: 'T list) (ys: 'U list) =
226-
Seq.fold2 f state xs ys
240+
let fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
241+
let mutable acc = state
242+
let mutable xs = xs
243+
let mutable ys = ys
244+
while not xs.IsEmpty && not ys.IsEmpty do
245+
acc <- folder acc xs.Head ys.Head
246+
xs <- xs.Tail
247+
ys <- ys.Tail
248+
acc
227249

228-
let foldBack2 f (xs: 'T list) (ys: 'U list) (state: 'State) =
229-
Seq.foldBack2 f xs ys state
250+
let foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (xs: 'T1 list) (ys: 'T2 list) (state: 'State) =
251+
// fold2 (fun acc x y -> folder x y acc) state (reverse xs) (reverse ys)
252+
Array.foldBack2 folder (toArray xs) (toArray ys) state
230253

231254
let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
232255
let rec loop st (node: 'T list) =
@@ -237,90 +260,123 @@ let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
237260
loop state root
238261
root.Tail
239262

240-
let scan f (state: 'State) (xs: 'T list) =
241-
Seq.scan f state xs |> ofSeq
263+
let scan (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
264+
let root = List.Empty
265+
let mutable node = root.AppendConsNoTail state
266+
let mutable acc = state
267+
let mutable xs = xs
268+
while not xs.IsEmpty do
269+
acc <- folder acc xs.Head
270+
node <- node.AppendConsNoTail acc
271+
xs <- xs.Tail
272+
node.SetConsTail List.Empty
273+
root.Tail
242274

243-
let scanBack f (xs: 'T list) (state: 'State) =
244-
Seq.scanBack f xs state |> ofSeq
275+
let scanBack (folder: 'T -> 'State -> 'State) (xs: 'T list) (state: 'State) =
276+
Array.scanBack folder (toArray xs) state |> ofArray
245277

246278
let append (xs: 'T list) (ys: 'T list) =
247279
fold (fun acc x -> List.Cons(x, acc)) ys (reverse xs)
248280

249-
let collect (f: 'T -> 'U list) (xs: 'T list) =
281+
let collect (mapping: 'T -> 'U list) (xs: 'T list) =
250282
let root = List.Empty
251283
let mutable node = root
252284
let mutable ys = xs
253285
while not ys.IsEmpty do
254-
let mutable zs = f ys.Head
286+
let mutable zs = mapping ys.Head
255287
while not zs.IsEmpty do
256288
node <- node.AppendConsNoTail zs.Head
257289
zs <- zs.Tail
258290
ys <- ys.Tail
259291
node.SetConsTail List.Empty
260292
root.Tail
261293

262-
let mapIndexed (f: int -> 'T -> 'U) (xs: 'T list) =
294+
let mapIndexed (mapping: int -> 'T -> 'U) (xs: 'T list) =
263295
let root = List.Empty
264-
let folder i (acc: 'U list) x = acc.AppendConsNoTail (f i x)
296+
let folder i (acc: 'U list) x = acc.AppendConsNoTail (mapping i x)
265297
let node = foldIndexed folder root xs
266298
node.SetConsTail List.Empty
267299
root.Tail
268300

269-
let map (f: 'T -> 'U) (xs: 'T list) =
270-
mapIndexed (fun i x -> f x) xs
301+
let map (mapping: 'T -> 'U) (xs: 'T list) =
302+
let root = List.Empty
303+
let folder (acc: 'U list) x = acc.AppendConsNoTail (mapping x)
304+
let node = fold folder root xs
305+
node.SetConsTail List.Empty
306+
root.Tail
271307

272308
let indexed xs =
273309
mapIndexed (fun i x -> (i, x)) xs
274310

275-
let map2 f xs ys =
276-
Seq.map2 f xs ys |> ofSeq
311+
let map2 (mapping: 'T1 -> 'T2 -> 'U) (xs: 'T1 list) (ys: 'T2 list) =
312+
let root = List.Empty
313+
let folder (acc: 'U list) x y = acc.AppendConsNoTail (mapping x y)
314+
let node = fold2 folder root xs ys
315+
node.SetConsTail List.Empty
316+
root.Tail
277317

278-
let mapIndexed2 f xs ys =
279-
Seq.mapi2 f xs ys |> ofSeq
318+
let mapIndexed2 (mapping: int -> 'T1 -> 'T2 -> 'U) (xs: 'T1 list) (ys: 'T2 list) =
319+
let rec loop i (acc: 'U list) (xs: 'T1 list) (ys: 'T2 list) =
320+
if xs.IsEmpty || ys.IsEmpty then acc
321+
else
322+
let node = acc.AppendConsNoTail (mapping i xs.Head ys.Head)
323+
loop (i + 1) node xs.Tail ys.Tail
324+
let root = List.Empty
325+
let node = loop 0 root xs ys
326+
node.SetConsTail List.Empty
327+
root.Tail
280328

281-
let map3 f xs ys zs =
282-
Seq.map3 f xs ys zs |> ofSeq
329+
let map3 (mapping: 'T1 -> 'T2 -> 'T3 -> 'U) (xs: 'T1 list) (ys: 'T2 list) (zs: 'T3 list) =
330+
let rec loop (acc: 'U list) (xs: 'T1 list) (ys: 'T2 list) (zs: 'T3 list) =
331+
if xs.IsEmpty || ys.IsEmpty || zs.IsEmpty then acc
332+
else
333+
let node = acc.AppendConsNoTail (mapping xs.Head ys.Head zs.Head)
334+
loop node xs.Tail ys.Tail zs.Tail
335+
let root = List.Empty
336+
let node = loop root xs ys zs
337+
node.SetConsTail List.Empty
338+
root.Tail
283339

284-
let mapFold (f: 'S -> 'T -> 'R * 'S) s xs =
340+
let mapFold (mapping: 'State -> 'T -> 'Result * 'State) (state: 'State) (xs: 'T list) =
285341
let folder (nxs, fs) x =
286-
let nx, fs = f fs x
342+
let nx, fs = mapping fs x
287343
List.Cons(nx, nxs), fs
288-
let nxs, s = fold folder (List.Empty, s) xs
289-
reverse nxs, s
344+
let nxs, state = fold folder (List.Empty, state) xs
345+
reverse nxs, state
290346

291-
let mapFoldBack (f: 'T -> 'S -> 'R * 'S) xs s =
292-
mapFold (fun s v -> f v s) s (reverse xs)
347+
let mapFoldBack (mapping: 'T -> 'State -> 'Result * 'State) (xs: 'T list) (state: 'State) =
348+
mapFold (fun acc x -> mapping x acc) state (reverse xs)
293349

294-
let iterate f xs =
295-
fold (fun () x -> f x) () xs
350+
let iterate action xs =
351+
fold (fun () x -> action x) () xs
296352

297-
let iterate2 f xs ys =
298-
fold2 (fun () x y -> f x y) () xs ys
353+
let iterate2 action xs ys =
354+
fold2 (fun () x y -> action x y) () xs ys
299355

300-
let iterateIndexed f xs =
301-
fold (fun i x -> f i x; i + 1) 0 xs |> ignore
356+
let iterateIndexed action xs =
357+
fold (fun i x -> action i x; i + 1) 0 xs |> ignore
302358

303-
let iterateIndexed2 f xs ys =
304-
fold2 (fun i x y -> f i x y; i + 1) 0 xs ys |> ignore
359+
let iterateIndexed2 action xs ys =
360+
fold2 (fun i x y -> action i x y; i + 1) 0 xs ys |> ignore
305361

306362
let tryPickIndexed (f: int -> 'T -> 'U option) (xs: 'T list) =
307-
let rec loop i (ys: 'T list) =
308-
if ys.IsEmpty then None
363+
let rec loop i (xs: 'T list) =
364+
if xs.IsEmpty then None
309365
else
310-
match f i ys.Head with
366+
match f i xs.Head with
311367
| Some _ as res -> res
312-
| None -> loop (i + 1) ys.Tail
368+
| None -> loop (i + 1) xs.Tail
313369
loop 0 xs
314370

315371
let tryPickIndexedBack (f: int -> 'T -> 'U option) (xs: 'T list) =
316-
let rec loop i acc (ys: 'T list) =
317-
if ys.IsEmpty then acc
372+
let rec loop i acc (xs: 'T list) =
373+
if xs.IsEmpty then acc
318374
else
319375
let result =
320-
match f i ys.Head with
376+
match f i xs.Head with
321377
| Some _ as res -> res
322378
| None -> acc
323-
loop (i + 1) result ys.Tail
379+
loop (i + 1) result xs.Tail
324380
loop 0 None xs
325381

326382
let tryPick f xs =
@@ -376,33 +432,43 @@ let findIndexBack f xs: int =
376432
| Some x -> x
377433

378434
let tryItem n (xs: 'T list) =
379-
let rec loop i (ys: 'T list) =
380-
if ys.IsEmpty then None
435+
let rec loop i (xs: 'T list) =
436+
if xs.IsEmpty then None
381437
else
382-
if i = n then Some ys.Head
383-
else loop (i + 1) ys.Tail
438+
if i = n then Some xs.Head
439+
else loop (i + 1) xs.Tail
384440
loop 0 xs
385441

386442
let item n (xs: 'T list) = xs.Item(n)
387443

388-
let filter f xs =
389-
fold (fun acc x ->
390-
if f x
391-
then List.Cons(x, acc)
392-
else acc) List.Empty xs
393-
|> reverse
394-
395-
let partition f xs =
396-
fold (fun (lacc, racc) x ->
397-
if f x then List.Cons(x, lacc), racc
398-
else lacc, List.Cons(x, racc)) (List.Empty, List.Empty) (reverse xs)
444+
let filter f (xs: 'T list) =
445+
let root = List.Empty
446+
let folder (acc: 'T list) x =
447+
if f x then acc.AppendConsNoTail x else acc
448+
let node = fold folder root xs
449+
node.SetConsTail List.Empty
450+
root.Tail
399451

400-
let choose f xs =
401-
fold (fun acc x ->
452+
let partition f (xs: 'T list) =
453+
let root1, root2 = List.Empty, List.Empty
454+
let folder (lacc: 'T list, racc: 'T list) x =
455+
if f x
456+
then lacc.AppendConsNoTail x, racc
457+
else lacc, racc.AppendConsNoTail x
458+
let node1, node2 = fold folder (root1, root2) xs
459+
node1.SetConsTail List.Empty
460+
node2.SetConsTail List.Empty
461+
root1.Tail, root2.Tail
462+
463+
let choose f (xs: 'T list) =
464+
let root = List.Empty
465+
let folder (acc: 'T list) x =
402466
match f x with
403-
| Some y -> List.Cons(y, acc)
404-
| None -> acc) List.Empty xs
405-
|> reverse
467+
| Some y -> acc.AppendConsNoTail y
468+
| None -> acc
469+
let node = fold folder root xs
470+
node.SetConsTail List.Empty
471+
root.Tail
406472

407473
let contains (value: 'T) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'T>) =
408474
tryFindIndex (fun v -> eq.Equals (value, v)) xs |> Option.isSome
@@ -413,11 +479,13 @@ let except (itemsToExclude: seq<'T>) (xs: 'T list) ([<Inject>] eq: System.Collec
413479
let cached = System.Collections.Generic.HashSet(itemsToExclude, eq)
414480
xs |> filter cached.Add
415481

416-
let initialize n f =
417-
let mutable res = List.Empty
482+
let initialize n (f: int -> 'T) =
483+
let root = List.Empty
484+
let mutable node = root
418485
for i = 0 to n - 1 do
419-
res <- List.Cons(f i, res)
420-
res |> reverse
486+
node <- node.AppendConsNoTail (f i)
487+
node.SetConsTail List.Empty
488+
root.Tail
421489

422490
let replicate n x =
423491
initialize n (fun _ -> x)
@@ -439,7 +507,7 @@ let forAll2 f xs ys =
439507
let exists f xs =
440508
tryFindIndex f xs |> Option.isSome
441509

442-
let rec exists2 f (xs: 'T list) (ys: 'U list) =
510+
let rec exists2 (f: 'T1 -> 'T2 -> bool) (xs: 'T1 list) (ys: 'T2 list) =
443511
match xs.IsEmpty, ys.IsEmpty with
444512
| true, true -> false
445513
| false, false -> f xs.Head ys.Head || exists2 f xs.Tail ys.Tail

0 commit comments

Comments
 (0)