@@ -54,17 +54,32 @@ function compareList<T>(self: List<T>, other: List<T>) {
5454 if ( other == null ) {
5555 return - 1 ;
5656 }
57- const selfLen = self . length ;
58- const otherLen = other . length ;
57+ const selfLen = self . Length ;
58+ const otherLen = other . Length ;
5959 const minLen = Math . min ( selfLen , otherLen ) ;
6060 for ( let i = 0 ; i < minLen ; i ++ ) {
61- const res = compare ( self . item ( i ) , other . item ( i ) ) ;
61+ const res = compare ( self . Item ( i ) , other . Item ( i ) ) ;
6262 if ( res !== 0 ) { return res ; }
6363 }
6464 return selfLen > otherLen ? 1 : ( selfLen < otherLen ? - 1 : 0 ) ;
6565 }
6666}
6767
68+ export function newList < T > ( vals : T [ ] ) : List < T > {
69+ return new List ( vals ) ;
70+ }
71+
72+ export function cons < T > ( head : T , tail : List < T > ) : List < T > {
73+ // If this points to the last index of the stack, push the new value into it.
74+ // Otherwise, this becomes an "actual" tail.
75+ if ( tail . vals . length === tail . idx + 1 ) {
76+ tail . vals . push ( head ) ;
77+ return new List ( tail . vals , tail . tail ) ;
78+ } else {
79+ return new List ( [ head ] , tail ) ;
80+ }
81+ }
82+
6883/**
6984 * F# list is represented in runtime by an optimized type that uses a stack (a reverted JS array)
7085 * to store the values, so we can a have a big list represented by a single object (plus the stack).
@@ -73,57 +88,52 @@ function compareList<T>(self: List<T>, other: List<T>) {
7388export class List < T > implements IEquatable < List < T > > , IComparable < List < T > > , Iterable < T > {
7489 public vals : T [ ] ;
7590 public idx : number ;
76- public _tail : List < T > | undefined ;
91+ public tail ? : List < T > ;
7792
78- constructor ( vals ?: T [ ] , idx ?: number ) {
93+ constructor ( vals ?: T [ ] , tail ?: List < T > , idx ?: number ) {
7994 this . vals = vals ?? [ ] ;
8095 this . idx = idx ?? this . vals . length - 1 ;
96+ this . tail = tail ;
8197 }
8298
83- add ( item : T ) : List < T > {
84- // If this points to the last index of the stack, push the new value into it.
85- // Otherwise, this becomes an "actual" tail.
86- if ( this . vals . length === this . idx + 1 ) {
87- this . vals . push ( item ) ;
88- return new List ( this . vals ) ;
99+ public Item ( i : number ) : T {
100+ if ( i < 0 ) {
101+ throw new Error ( "Index out of range" ) ;
102+ } else if ( i <= this . idx ) {
103+ return this . vals [ this . idx - i ] ;
104+ } else if ( this . tail ) {
105+ return this . tail . Item ( i - this . idx - 1 ) ;
89106 } else {
90- const li = new List ( [ item ] ) ;
91- li . _tail = this ;
92- return li ;
93- }
94- }
95-
96- /** Unsafe, check length before calling it */
97- public item ( i : number ) : T | undefined {
98- let rev_i = this . idx - i ;
99- if ( rev_i >= 0 ) {
100- return this . vals [ rev_i ] ;
101- } else if ( this . _tail ) {
102- return this . _tail . item ( rev_i * - 1 - 1 ) ;
107+ throw new Error ( "Index out of range" ) ;
103108 }
104- return undefined ;
105109 }
106110
107- /** Unsafe, check isEmpty before calling it */
108- public get head ( ) : T | undefined {
109- return this . vals [ this . idx ] ;
111+ public get Head ( ) : T {
112+ if ( this . idx >= 0 ) {
113+ return this . vals [ this . idx ] ;
114+ } else if ( this . idx < 0 && this . tail ) {
115+ return this . tail . Head ;
116+ } else {
117+ throw new Error ( "List was empty" ) ;
118+ }
110119 }
111120
112- public get tail ( ) : List < T > | undefined {
113- if ( this . idx === 0 && this . _tail ) {
114- return this . _tail ;
121+ public get Tail ( ) : List < T > | undefined {
122+ if ( this . idx === 0 && this . tail ) {
123+ return this . tail ;
115124 } else if ( this . idx >= 0 ) {
116- return new List ( this . vals , this . idx - 1 ) ;
125+ return new List ( this . vals , this . tail , this . idx - 1 ) ;
126+ } else {
127+ return this . tail ?. Tail ;
117128 }
118- return undefined ;
119129 }
120130
121- public get isEmpty ( ) {
122- return this . idx < 0 ;
131+ public get IsEmpty ( ) : boolean {
132+ return this . idx < 0 && ( this . tail ?. IsEmpty ?? true ) ;
123133 }
124134
125- public get length ( ) : number {
126- return this . idx + 1 + ( this . _tail ?. length ?? 0 ) ;
135+ public get Length ( ) : number {
136+ return this . idx + 1 + ( this . tail ?. Length ?? 0 ) ;
127137 }
128138
129139 public toString ( ) {
@@ -139,15 +149,13 @@ export class List<T> implements IEquatable<List<T>>, IComparable<List<T>>, Itera
139149 let li : List < T > = this ;
140150 return {
141151 next : ( ) : IteratorResult < T > => {
142- if ( curIdx < 0 ) {
143- if ( li . _tail ) {
144- li = li . _tail ;
145- curIdx = li . idx ;
146- } else {
147- return { done : true , value : undefined } ;
148- }
152+ while ( curIdx < 0 && li . tail ) {
153+ li = li . tail ;
154+ curIdx = li . idx ;
149155 }
150- return { done : false , value : li . vals [ curIdx -- ] } ;
156+ return ( curIdx < 0 )
157+ ? { done : true , value : undefined }
158+ : { done : false , value : li . vals [ curIdx -- ] } ;
151159 }
152160 } ;
153161 }
0 commit comments