Skip to content

Commit

Permalink
List type updates
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave committed Feb 16, 2021
1 parent f895a62 commit 10dcd15
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 79 deletions.
6 changes: 4 additions & 2 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1845,8 +1845,10 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex
match i.CompiledName, args with
| "ToSeq", [arg] -> Some arg
| "OfSeq", [arg] -> toArray r t arg |> Some
| "OfList", [arg] -> toArray r t arg |> Some
| "ToList", _ -> Helper.LibCall(com, "List", "ofArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
| "OfList", [arg] ->
Helper.LibCall(com, "List", "toArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
| "ToList", args ->
Helper.LibCall(com, "List", "ofArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some
| ("Length" | "Count"), [arg] -> get r t arg "length" |> Some
| "Item", [idx; ar] -> getExpr r t ar idx |> Some
| "Get", [ar; idx] -> getExpr r t ar idx |> Some
Expand Down
200 changes: 123 additions & 77 deletions src/fable-library/List.fs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ module SR =
let listsHadDifferentLengths = "The lists had different lengths."
let notEnoughElements = "The input sequence has an insufficient number of elements."

[<Struct>]
[<CustomEquality; CustomComparison>]
// [<CompiledName("FSharpList`1")>]
type List<'T when 'T: comparison> =
Expand Down Expand Up @@ -186,6 +185,10 @@ let toArray (xs: 'T list) =
loop 0 xs
res

// let rec fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
// if xs.IsEmpty then state
// else fold folder (folder state xs.Head) xs.Tail

let fold (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
let mutable acc = state
let mutable xs = xs
Expand All @@ -207,6 +210,46 @@ let foldIndexed (folder: int -> 'State -> 'T -> 'State) (state: 'State) (xs: 'T
else loop (i + 1) (folder i acc xs.Head) xs.Tail
loop 0 state xs

// let rec fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
// if xs.IsEmpty || ys.IsEmpty then state
// else fold2 folder (folder state xs.Head ys.Head) xs.Tail ys.Tail

let fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
let mutable acc = state
let mutable xs = xs
let mutable ys = ys
while not xs.IsEmpty && not ys.IsEmpty do
acc <- folder acc xs.Head ys.Head
xs <- xs.Tail
ys <- ys.Tail
acc

let foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (xs: 'T1 list) (ys: 'T2 list) (state: 'State) =
// fold2 (fun acc x y -> folder x y acc) state (reverse xs) (reverse ys)
Array.foldBack2 folder (toArray xs) (toArray ys) state

let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
let rec loop acc (node: 'T list) =
match gen acc with
| None -> node
| Some (x, acc) -> loop acc (node.AppendConsNoTail x)
let root = List.Empty
let node = loop state root
node.SetConsTail List.Empty
root.Tail

let iterate action xs =
fold (fun () x -> action x) () xs

let iterate2 action xs ys =
fold2 (fun () x y -> action x y) () xs ys

let iterateIndexed action xs =
fold (fun i x -> action i x; i + 1) 0 xs |> ignore

let iterateIndexed2 action xs ys =
fold2 (fun i x y -> action i x y; i + 1) 0 xs ys |> ignore

let toSeq (xs: 'T list): 'T seq =
xs :> System.Collections.Generic.IEnumerable<'T>

Expand All @@ -221,45 +264,27 @@ let ofArray (xs: 'T[]) =

let ofSeq (xs: seq<'T>): 'T list =
match xs with
| :? list<'T> as lst -> lst
| :? array<'T> as arr -> ofArray arr
| :? array<'T> as xs -> ofArray xs
| :? list<'T> as xs -> xs
| _ ->
let root = List.Empty
let node = Seq.fold (fun (acc: 'T list) x -> acc.AppendConsNoTail x) root xs
let mutable node = root
for x in xs do
node <- node.AppendConsNoTail x
node.SetConsTail List.Empty
root.Tail

let concat (lists: seq<'T list>) =
let root = List.Empty
let mutable node = root
for xs in lists do
node <- fold (fun acc x -> acc.AppendConsNoTail x) node xs
let action xs = node <- fold (fun acc x -> acc.AppendConsNoTail x) node xs
match lists with
| :? array<'T list> as xs -> Array.iter action xs
| :? list<'T list> as xs -> iterate action xs
| _ -> for xs in lists do action xs
node.SetConsTail List.Empty
root.Tail

let fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (xs: 'T1 list) (ys: 'T2 list) =
let mutable acc = state
let mutable xs = xs
let mutable ys = ys
while not xs.IsEmpty && not ys.IsEmpty do
acc <- folder acc xs.Head ys.Head
xs <- xs.Tail
ys <- ys.Tail
acc

let foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (xs: 'T1 list) (ys: 'T2 list) (state: 'State) =
// fold2 (fun acc x y -> folder x y acc) state (reverse xs) (reverse ys)
Array.foldBack2 folder (toArray xs) (toArray ys) state

let unfold (gen: 'State -> ('T * 'State) option) (state: 'State) =
let rec loop st (node: 'T list) =
match gen st with
| None -> node.SetConsTail List.Empty
| Some (x, st) -> loop st (node.AppendConsNoTail x)
let root = List.Empty
loop state root
root.Tail

let scan (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
let root = List.Empty
let mutable node = root.AppendConsNoTail state
Expand All @@ -273,7 +298,8 @@ let scan (folder: 'State -> 'T -> 'State) (state: 'State) (xs: 'T list) =
root.Tail

let scanBack (folder: 'T -> 'State -> 'State) (xs: 'T list) (state: 'State) =
Array.scanBack folder (toArray xs) state |> ofArray
Array.scanBack folder (toArray xs) state
|> ofArray

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

let mapFold (mapping: 'State -> 'T -> 'Result * 'State) (state: 'State) (xs: 'T list) =
let folder (nxs, fs) x =
let nx, fs = mapping fs x
List.Cons(nx, nxs), fs
let nxs, state = fold folder (List.Empty, state) xs
reverse nxs, state
let folder (node: 'Result list, st) x =
let r, st = mapping st x
node.AppendConsNoTail r, st
let root = List.Empty
let node, state = fold folder (root, state) xs
node.SetConsTail List.Empty
root.Tail, state

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

let iterate action xs =
fold (fun () x -> action x) () xs

let iterate2 action xs ys =
fold2 (fun () x y -> action x y) () xs ys

let iterateIndexed action xs =
fold (fun i x -> action i x; i + 1) 0 xs |> ignore

let iterateIndexed2 action xs ys =
fold2 (fun i x y -> action i x y; i + 1) 0 xs ys |> ignore

let tryPickIndexed (f: int -> 'T -> 'U option) (xs: 'T list) =
let rec loop i (xs: 'T list) =
if xs.IsEmpty then None
Expand Down Expand Up @@ -525,21 +541,21 @@ let zip xs ys =
let zip3 xs ys zs =
map3 (fun x y z -> x, y, z) xs ys zs

let sortWith (comparison: 'T -> 'T -> int) (xs: 'T list): 'T list =
let values = ResizeArray(xs)
values.Sort(System.Comparison<_>(comparison))
values |> ofSeq
let sortWith (comparer: 'T -> 'T -> int) (xs: 'T list) =
let arr = toArray xs
Array.sortInPlaceWith comparer arr
arr |> ofArray

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

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

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

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

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

let permute f (xs: 'T list) =
Array.ofSeq xs
toArray xs
|> Array.permute f
|> ofArray

let chunkBySize (chunkSize: int) (xs: 'T list): 'T list list =
Array.ofSeq xs
toArray xs
|> Array.chunkBySize chunkSize
|> Array.map ofArray
|> ofArray
|> map ofArray

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

let skipWhile predicate (xs: 'T list) =
Seq.skipWhile predicate xs |> ofSeq

let take i xs =
Seq.take i xs |> ofSeq
let rec skipWhile predicate (xs: 'T list) =
if xs.IsEmpty then xs
elif not (predicate xs.Head) then xs
else skipWhile predicate xs.Tail

let take count (xs: 'T list) =
if count < 0 then invalidArg "count" SR.inputMustBeNonNegative
let rec loop i (acc: 'T list) (xs: 'T list) =
if i <= 0 then acc
elif xs.IsEmpty then invalidArg "list" SR.notEnoughElements
else loop (i - 1) (acc.AppendConsNoTail xs.Head) xs.Tail
let root = List.Empty
let node = loop count root xs
node.SetConsTail List.Empty
root.Tail

let takeWhile predicate (xs: 'T list) =
Seq.takeWhile predicate xs |> ofSeq
let rec loop (acc: 'T list) (xs: 'T list) =
if xs.IsEmpty then acc
elif not (predicate xs.Head) then acc
else loop (acc.AppendConsNoTail xs.Head) xs.Tail
let root = List.Empty
let node = loop root xs
node.SetConsTail List.Empty
root.Tail

let truncate i xs =
Seq.truncate i xs |> ofSeq
let truncate count (xs: 'T list) =
let rec loop i (acc: 'T list) (xs: 'T list) =
if i <= 0 then acc
elif xs.IsEmpty then acc
else loop (i - 1) (acc.AppendConsNoTail xs.Head) xs.Tail
let root = List.Empty
let node = loop count root xs
node.SetConsTail List.Empty
root.Tail

let getSlice (startIndex: int option) (endIndex: int option) (xs: 'T list) =
let len = length xs
Expand Down Expand Up @@ -656,24 +698,28 @@ let where predicate (xs: 'T list) =
filter predicate xs

let pairwise (xs: 'T list) =
Seq.pairwise xs |> ofSeq
toArray xs
|> Array.pairwise
|> ofArray

let windowed (windowSize: int) (xs: 'T list): 'T list list =
Seq.windowed windowSize xs
|> ofSeq
|> map ofArray
toArray xs
|> Array.windowed windowSize
|> Array.map ofArray
|> ofArray

let splitInto (chunks: int) (xs: 'T list): 'T list list =
Array.ofSeq xs
toArray xs
|> Array.splitInto chunks
|> Array.map ofArray
|> ofArray
|> map ofArray

let transpose (lists: seq<'T list>): 'T list list =
lists
|> Seq.transpose
|> Seq.map ofSeq
|> ofSeq
|> Seq.map toArray
|> Array.transpose
|> Array.map ofArray
|> ofArray

// let rev = reverse
// let init = initialize
Expand Down
4 changes: 4 additions & 0 deletions src/fable-library/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"private": true,
"type": "module"
}

0 comments on commit 10dcd15

Please sign in to comment.