Skip to content

Commit fb508f7

Browse files
committed
List type updates
1 parent f895a62 commit fb508f7

File tree

3 files changed

+136
-85
lines changed

3 files changed

+136
-85
lines changed

src/Fable.Transforms/Replacements.fs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,8 +1845,10 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex
18451845
match i.CompiledName, args with
18461846
| "ToSeq", [arg] -> Some arg
18471847
| "OfSeq", [arg] -> toArray r t arg |> Some
1848-
| "OfList", [arg] -> toArray r t arg |> Some
1849-
| "ToList", _ -> Helper.LibCall(com, "List", "ofArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
1848+
| "OfList", [arg] ->
1849+
Helper.LibCall(com, "List", "toArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
1850+
| "ToList", args ->
1851+
Helper.LibCall(com, "List", "ofArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
18501852
| ("Length" | "Count"), [arg] -> get r t arg "length" |> Some
18511853
| "Item", [idx; ar] -> getExpr r t ar idx |> Some
18521854
| "Get", [ar; idx] -> getExpr r t ar idx |> Some

src/fable-library/List.fs

Lines changed: 128 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module LinkedList
22

3-
open Fable.Core
4-
53
module SR =
64
let indexOutOfBounds = "The index was outside the range of elements in the list."
75
let inputListWasEmpty = "List was empty"
@@ -12,11 +10,10 @@ module SR =
1210
let listsHadDifferentLengths = "The lists had different lengths."
1311
let notEnoughElements = "The input sequence has an insufficient number of elements."
1412

15-
[<Struct>]
1613
[<CustomEquality; CustomComparison>]
1714
// [<CompiledName("FSharpList`1")>]
18-
type List<'T when 'T: comparison> =
19-
{ head: 'T; mutable tail: List<'T> option }
15+
type LinkedList<'T when 'T: comparison> =
16+
{ head: 'T; mutable tail: LinkedList<'T> option }
2017

2118
static member inline Empty: 'T list = { head = Unchecked.defaultof<'T>; tail = None }
2219
static member inline Cons (x: 'T, xs: 'T list) = { head = x; tail = Some xs }
@@ -107,7 +104,7 @@ type List<'T when 'T: comparison> =
107104
member xs.GetEnumerator(): System.Collections.IEnumerator =
108105
((xs :> System.Collections.Generic.IEnumerable<'T>).GetEnumerator() :> System.Collections.IEnumerator)
109106

110-
and ListEnumerator<'T when 'T: comparison>(xs: List<'T>) =
107+
and ListEnumerator<'T when 'T: comparison>(xs: 'T list) =
111108
let mutable it = xs
112109
let mutable current = Unchecked.defaultof<'T>
113110
interface System.Collections.Generic.IEnumerator<'T> with
@@ -127,7 +124,8 @@ and ListEnumerator<'T when 'T: comparison>(xs: List<'T>) =
127124
interface System.IDisposable with
128125
member __.Dispose() = ()
129126

130-
and 'T list when 'T: comparison = List<'T>
127+
and 'T list when 'T: comparison = LinkedList<'T>
128+
and List<'T> when 'T: comparison = LinkedList<'T>
131129

132130
// [<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
133131
// [<RequireQualifiedAccess>]
@@ -186,6 +184,10 @@ let toArray (xs: 'T list) =
186184
loop 0 xs
187185
res
188186

187+
// let rec fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
188+
// if xs.IsEmpty then state
189+
// else fold folder (folder state xs.Head) xs.Tail
190+
189191
let fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
190192
let mutable acc = state
191193
let mutable xs = xs
@@ -207,6 +209,46 @@ let foldIndexed (folder: int -> 'State -> 'T -> 'State) (state: 'State) (xs: 'T
207209
else loop (i + 1) (folder i acc xs.Head) xs.Tail
208210
loop 0 state xs
209211

212+
// let rec fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
213+
// if xs.IsEmpty || ys.IsEmpty then state
214+
// else fold2 folder (folder state xs.Head ys.Head) xs.Tail ys.Tail
215+
216+
let fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
217+
let mutable acc = state
218+
let mutable xs = xs
219+
let mutable ys = ys
220+
while not xs.IsEmpty && not ys.IsEmpty do
221+
acc <- folder acc xs.Head ys.Head
222+
xs <- xs.Tail
223+
ys <- ys.Tail
224+
acc
225+
226+
let foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (xs: 'T1 list) (ys: 'T2 list) (state: 'State) =
227+
// fold2 (fun acc x y -> folder x y acc) state (reverse xs) (reverse ys)
228+
Array.foldBack2 folder (toArray xs) (toArray ys) state
229+
230+
let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
231+
let rec loop acc (node: 'T list) =
232+
match gen acc with
233+
| None -> node
234+
| Some (x, acc) -> loop acc (node.AppendConsNoTail x)
235+
let root = List.Empty
236+
let node = loop state root
237+
node.SetConsTail List.Empty
238+
root.Tail
239+
240+
let iterate action xs =
241+
fold (fun () x -> action x) () xs
242+
243+
let iterate2 action xs ys =
244+
fold2 (fun () x y -> action x y) () xs ys
245+
246+
let iterateIndexed action xs =
247+
fold (fun i x -> action i x; i + 1) 0 xs |> ignore
248+
249+
let iterateIndexed2 action xs ys =
250+
fold2 (fun i x y -> action i x y; i + 1) 0 xs ys |> ignore
251+
210252
let toSeq (xs: 'T list): 'T seq =
211253
xs :> System.Collections.Generic.IEnumerable<'T>
212254

@@ -221,45 +263,27 @@ let ofArray (xs: 'T[]) =
221263

222264
let ofSeq (xs: seq<'T>): 'T list =
223265
match xs with
224-
| :? list<'T> as lst -> lst
225-
| :? array<'T> as arr -> ofArray arr
266+
| :? array<'T> as xs -> ofArray xs
267+
| :? list<'T> as xs -> xs
226268
| _ ->
227269
let root = List.Empty
228-
let node = Seq.fold (fun (acc: 'T list) x -> acc.AppendConsNoTail x) root xs
270+
let mutable node = root
271+
for x in xs do
272+
node <- node.AppendConsNoTail x
229273
node.SetConsTail List.Empty
230274
root.Tail
231275

232276
let concat (lists: seq<'T list>) =
233277
let root = List.Empty
234278
let mutable node = root
235-
for xs in lists do
236-
node <- fold (fun acc x -> acc.AppendConsNoTail x) node xs
279+
let action xs = node <- fold (fun acc x -> acc.AppendConsNoTail x) node xs
280+
match lists with
281+
| :? array<'T list> as xs -> Array.iter action xs
282+
| :? list<'T list> as xs -> iterate action xs
283+
| _ -> for xs in lists do action xs
237284
node.SetConsTail List.Empty
238285
root.Tail
239286

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
249-
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
253-
254-
let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
255-
let rec loop st (node: 'T list) =
256-
match gen st with
257-
| None -> node.SetConsTail List.Empty
258-
| Some (x, st) -> loop st (node.AppendConsNoTail x)
259-
let root = List.Empty
260-
loop state root
261-
root.Tail
262-
263287
let scan (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
264288
let root = List.Empty
265289
let mutable node = root.AppendConsNoTail state
@@ -273,7 +297,8 @@ let scan (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
273297
root.Tail
274298

275299
let scanBack (folder: 'T -> 'State -> 'State) (xs: 'T list) (state: 'State) =
276-
Array.scanBack folder (toArray xs) state |> ofArray
300+
Array.scanBack folder (toArray xs) state
301+
|> ofArray
277302

278303
let append (xs: 'T list) (ys: 'T list) =
279304
fold (fun acc x -> List.Cons(x, acc)) ys (reverse xs)
@@ -338,27 +363,17 @@ let map3 (mapping: 'T1 -> 'T2 -> 'T3 -> 'U) (xs: 'T1 list) (ys: 'T2 list) (zs: '
338363
root.Tail
339364

340365
let mapFold (mapping: 'State -> 'T -> 'Result * 'State) (state: 'State) (xs: 'T list) =
341-
let folder (nxs, fs) x =
342-
let nx, fs = mapping fs x
343-
List.Cons(nx, nxs), fs
344-
let nxs, state = fold folder (List.Empty, state) xs
345-
reverse nxs, state
366+
let folder (node: 'Result list, st) x =
367+
let r, st = mapping st x
368+
node.AppendConsNoTail r, st
369+
let root = List.Empty
370+
let node, state = fold folder (root, state) xs
371+
node.SetConsTail List.Empty
372+
root.Tail, state
346373

347374
let mapFoldBack (mapping: 'T -> 'State -> 'Result * 'State) (xs: 'T list) (state: 'State) =
348375
mapFold (fun acc x -> mapping x acc) state (reverse xs)
349376

350-
let iterate action xs =
351-
fold (fun () x -> action x) () xs
352-
353-
let iterate2 action xs ys =
354-
fold2 (fun () x y -> action x y) () xs ys
355-
356-
let iterateIndexed action xs =
357-
fold (fun i x -> action i x; i + 1) 0 xs |> ignore
358-
359-
let iterateIndexed2 action xs ys =
360-
fold2 (fun i x y -> action i x y; i + 1) 0 xs ys |> ignore
361-
362377
let tryPickIndexed (f: int -> 'T -> 'U option) (xs: 'T list) =
363378
let rec loop i (xs: 'T list) =
364379
if xs.IsEmpty then None
@@ -525,21 +540,21 @@ let zip xs ys =
525540
let zip3 xs ys zs =
526541
map3 (fun x y z -> x, y, z) xs ys zs
527542

528-
let sortWith (comparison: 'T -> 'T -> int) (xs: 'T list): 'T list =
529-
let values = ResizeArray(xs)
530-
values.Sort(System.Comparison<_>(comparison))
531-
values |> ofSeq
543+
let sortWith (comparer: 'T -> 'T -> int) (xs: 'T list) =
544+
let arr = toArray xs
545+
Array.sortInPlaceWith comparer arr
546+
arr |> ofArray
532547

533-
let sort (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T list =
548+
let sort (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>) =
534549
sortWith (fun x y -> comparer.Compare(x, y)) xs
535550

536-
let sortBy (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T list =
551+
let sortBy (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>) =
537552
sortWith (fun x y -> comparer.Compare(projection x, projection y)) xs
538553

539-
let sortDescending (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>): 'T list =
554+
let sortDescending (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>) =
540555
sortWith (fun x y -> comparer.Compare(x, y) * -1) xs
541556

542-
let sortByDescending (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>): 'T list =
557+
let sortByDescending (projection: 'T -> 'U) (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'U>) =
543558
sortWith (fun x y -> comparer.Compare(projection x, projection y) * -1) xs
544559

545560
let sum (xs: 'T list) ([<Inject>] adder: IGenericAdder<'T>): 'T =
@@ -569,30 +584,56 @@ let averageBy (f: 'T -> 'T2) (xs: 'T list) ([<Inject>] averager: IGenericAverage
569584
averager.DivideByInt(total, length xs)
570585

571586
let permute f (xs: 'T list) =
572-
Array.ofSeq xs
587+
toArray xs
573588
|> Array.permute f
574589
|> ofArray
575590

576591
let chunkBySize (chunkSize: int) (xs: 'T list): 'T list list =
577-
Array.ofSeq xs
592+
toArray xs
578593
|> Array.chunkBySize chunkSize
594+
|> Array.map ofArray
579595
|> ofArray
580-
|> map ofArray
581596

582-
let skip i (xs: 'T list) =
583-
Seq.skip i xs |> ofSeq
597+
let rec skip count (xs: 'T list) =
598+
if count <= 0 then xs
599+
elif xs.IsEmpty then invalidArg "list" SR.notEnoughElements
600+
else skip (count - 1) xs.Tail
584601

585-
let skipWhile predicate (xs: 'T list) =
586-
Seq.skipWhile predicate xs |> ofSeq
587-
588-
let take i xs =
589-
Seq.take i xs |> ofSeq
602+
let rec skipWhile predicate (xs: 'T list) =
603+
if xs.IsEmpty then xs
604+
elif not (predicate xs.Head) then xs
605+
else skipWhile predicate xs.Tail
606+
607+
let take count (xs: 'T list) =
608+
if count < 0 then invalidArg "count" SR.inputMustBeNonNegative
609+
let rec loop i (acc: 'T list) (xs: 'T list) =
610+
if i <= 0 then acc
611+
elif xs.IsEmpty then invalidArg "list" SR.notEnoughElements
612+
else loop (i - 1) (acc.AppendConsNoTail xs.Head) xs.Tail
613+
let root = List.Empty
614+
let node = loop count root xs
615+
node.SetConsTail List.Empty
616+
root.Tail
590617

591618
let takeWhile predicate (xs: 'T list) =
592-
Seq.takeWhile predicate xs |> ofSeq
619+
let rec loop (acc: 'T list) (xs: 'T list) =
620+
if xs.IsEmpty then acc
621+
elif not (predicate xs.Head) then acc
622+
else loop (acc.AppendConsNoTail xs.Head) xs.Tail
623+
let root = List.Empty
624+
let node = loop root xs
625+
node.SetConsTail List.Empty
626+
root.Tail
593627

594-
let truncate i xs =
595-
Seq.truncate i xs |> ofSeq
628+
let truncate count (xs: 'T list) =
629+
let rec loop i (acc: 'T list) (xs: 'T list) =
630+
if i <= 0 then acc
631+
elif xs.IsEmpty then acc
632+
else loop (i - 1) (acc.AppendConsNoTail xs.Head) xs.Tail
633+
let root = List.Empty
634+
let node = loop count root xs
635+
node.SetConsTail List.Empty
636+
root.Tail
596637

597638
let getSlice (startIndex: int option) (endIndex: int option) (xs: 'T list) =
598639
let len = length xs
@@ -656,24 +697,28 @@ let where predicate (xs: 'T list) =
656697
filter predicate xs
657698

658699
let pairwise (xs: 'T list) =
659-
Seq.pairwise xs |> ofSeq
700+
toArray xs
701+
|> Array.pairwise
702+
|> ofArray
660703

661704
let windowed (windowSize: int) (xs: 'T list): 'T list list =
662-
Seq.windowed windowSize xs
663-
|> ofSeq
664-
|> map ofArray
705+
toArray xs
706+
|> Array.windowed windowSize
707+
|> Array.map ofArray
708+
|> ofArray
665709

666710
let splitInto (chunks: int) (xs: 'T list): 'T list list =
667-
Array.ofSeq xs
711+
toArray xs
668712
|> Array.splitInto chunks
713+
|> Array.map ofArray
669714
|> ofArray
670-
|> map ofArray
671715

672716
let transpose (lists: seq<'T list>): 'T list list =
673717
lists
674-
|> Seq.transpose
675-
|> Seq.map ofSeq
676-
|> ofSeq
718+
|> Seq.map toArray
719+
|> Array.transpose
720+
|> Array.map ofArray
721+
|> ofArray
677722

678723
// let rev = reverse
679724
// let init = initialize

src/fable-library/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"private": true,
3+
"type": "module"
4+
}

0 commit comments

Comments
 (0)