Skip to content

Commit

Permalink
Updating list-ops test generic types parameters (#1477)
Browse files Browse the repository at this point in the history
* Fix ci workflow

* Updating list-ops test generic types parameters

* Updating `proof.ci.ts` with generic types

* Format manually

---------

Co-authored-by: Derk-Jan Karrenbeld <[email protected]>
  • Loading branch information
Shoghy and SleeplessByte authored Aug 5, 2024
1 parent e5caeaa commit 2ca3200
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 72 deletions.
103 changes: 49 additions & 54 deletions exercises/practice/list-ops/.meta/proof.ci.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const Null: Cons = {
const Null: Cons<undefined> = {
get value() {
return undefined
},
Expand All @@ -10,17 +10,17 @@ const Null: Cons = {
return this.value
},

push(item): Cons {
push<T>(item: T): Cons<T> {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return new Cons(item, this)
return new Cons(item, this) as Cons<T>
},
length() {
return 0
},
append(other: Cons): Cons {
append<T>(other: Cons<T>): Cons<T> {
return other
},
concat(): Cons {
concat(): Cons<undefined> {
return this
},
forEach(): void {
Expand All @@ -38,27 +38,27 @@ const Null: Cons = {
): TReturn {
return initial as TReturn
},
filter(): Cons {
filter(): Cons<undefined> {
return Null
},
reverse(): Cons {
reverse(): Cons<undefined> {
return this
},
map(): Cons {
return this
map<TReturn>(): Cons<TReturn> {
return this as Cons<TReturn>
},
}
class Cons {
class Cons<T> {
constructor(
public readonly value: unknown,
public next: Cons = Null
public readonly value: T,
public next: Cons<T> = Null as Cons<T>
) {}

public get(i: number): unknown {
public get(i: number): T | undefined {
return i === 0 ? this.value : this.next.get(i - 1)
}

public push(item: unknown): this {
public push(item: T): this {
this.next = this.next.push(item)
return this
}
Expand All @@ -67,83 +67,78 @@ class Cons {
return 1 + this.next.length()
}

public append(other: Cons): Cons {
public append(other: Cons<T>): Cons<T> {
return other.foldl((result, item) => result.push(item), this)
}

public concat(others: Cons): Cons {
return others.foldl<Cons, Cons>(
(result, other) => result.append(other),
this
)
public concat(others: Cons<Cons<T>>): Cons<T> {
return others.foldl<Cons<T>>((result, other) => result.append(other), this)
}

public foldl<TValue = unknown>(
callback: (initial: TValue, value: TValue) => TValue
): TValue
public foldl<TValue = unknown, TReturn = unknown>(
callback: (initial: TReturn, value: TValue) => TReturn,
public foldl<TReturn = unknown>(
callback: (initial: TReturn, value: T) => TReturn
): TReturn
public foldl<TReturn = unknown>(
callback: (initial: TReturn, value: T) => TReturn,
initial: TReturn
): TReturn

public foldl<TValue = unknown, TReturn = unknown>(
callback: (initial: TReturn | undefined, value: TValue) => TReturn,
public foldl<TReturn = unknown>(
callback: (initial: TReturn | undefined, value: T) => TReturn,
initial?: TReturn
): TReturn {
return this.next.foldl<TValue, TReturn>(
callback,
callback(initial, this.value as TValue)
)
return this.next.foldl<TReturn>(callback, callback(initial, this.value))
}

public forEach(callback: (value: unknown) => void): void {
public forEach(callback: (value: T) => void): void {
this.foldl((_, item) => callback(item))
}

public foldr<TValue = unknown>(
callback: (initial: TValue, value: TValue) => TValue
): TValue
public foldr<TValue = unknown, TReturn = unknown>(
callback: (initial: TReturn, value: TValue) => TReturn,
public foldr<TReturn = unknown>(
callback: (initial: TReturn, value: T) => TReturn
): TReturn
public foldr<TReturn = unknown>(
callback: (initial: TReturn, value: T) => TReturn,
initial: TReturn
): TReturn

public foldr<TValue = unknown, TReturn = unknown>(
callback: (initial: TReturn, value: TValue) => TReturn,
public foldr<TReturn = unknown>(
callback: (initial: TReturn, value: T) => TReturn,
initial?: TReturn
): TReturn {
return callback(
this.next.foldr<TValue, TReturn>(callback, initial as TReturn),
this.value as TValue
this.next.foldr<TReturn>(
callback as (initial: TReturn, value: T | undefined) => TReturn,
initial as TReturn
),
this.value
)
}

public filter<TValue = unknown>(predicate: (value: TValue) => boolean): Cons {
return this.foldl<TValue, Cons>(
public filter(predicate: (value: T) => boolean): Cons<T> {
return this.foldl<Cons<T>>(
(result, item) => (predicate(item) && result.push(item)) || result,
Null
Null as Cons<T>
)
}

public map<TValue = unknown, TReturn = unknown>(
expression: (value: TValue) => TReturn
): Cons {
return this.foldl<TValue, Cons>(
public map<TReturn = unknown>(
expression: (value: T) => TReturn
): Cons<TReturn> {
return this.foldl(
(result, item) => result.push(expression(item)),
Null
Null as Cons<TReturn>
)
}

public reverse(): Cons {
public reverse(): Cons<T> {
return this.next.reverse().push(this.value)
}
}
export class List {
public static create(...values: unknown[]): Cons {
public static create<T>(...values: T[]): Cons<T> {
const [head, ...tail] = values

if (head === undefined) {
return Null
return Null as Cons<T>
}

return new Cons(head, List.create(...tail))
Expand Down
36 changes: 18 additions & 18 deletions exercises/practice/list-ops/list-ops.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ describe('append entries to a list and return the new list', () => {
})

xit('list to empty list', () => {
const list1 = List.create()
const list1 = List.create<number>()
const list2 = List.create(1, 2, 3, 4)
expect(list1.append(list2)).toEqual(list2)
})

xit('empty list to list', () => {
const list1 = List.create(1, 2, 3, 4)
const list2 = List.create()
const list2 = List.create<number>()
expect(list1.append(list2)).toEqual(list1)
})

Expand All @@ -87,14 +87,14 @@ describe('append entries to a list and return the new list', () => {
describe('concat lists and lists of lists into new list', () => {
xit('empty list', () => {
const list1 = List.create()
const list2 = List.create()
const list2 = List.create<ReturnType<typeof List.create>>()
expect(list1.concat(list2)).toHaveValues()
})

xit('list of lists', () => {
const list1 = List.create(1, 2)
const list2 = List.create(3)
const list3 = List.create()
const list3 = List.create<number>()
const list4 = List.create(4, 5, 6)
const listOfLists = List.create(list2, list3, list4)
expect(list1.concat(listOfLists)).toHaveValues(1, 2, 3, 4, 5, 6)
Expand All @@ -103,13 +103,13 @@ describe('concat lists and lists of lists into new list', () => {

describe('filter list returning only values that satisfy the filter function', () => {
xit('empty list', () => {
const list1 = List.create()
expect(list1.filter<number>((el) => el % 2 === 1)).toHaveValues()
const list1 = List.create<number>()
expect(list1.filter((el) => el % 2 === 1)).toHaveValues()
})

xit('non empty list', () => {
const list1 = List.create(1, 2, 3, 5)
expect(list1.filter<number>((el) => el % 2 === 1)).toHaveValues(1, 3, 5)
expect(list1.filter((el) => el % 2 === 1)).toHaveValues(1, 3, 5)
})
})

Expand All @@ -127,47 +127,47 @@ describe('returns the length of a list', () => {

describe('returns a list of elements whose values equal the list value transformed by the mapping function', () => {
xit('empty list', () => {
const list1 = List.create()
expect(list1.map<number>((el) => ++el)).toHaveValues()
const list1 = List.create<number>()
expect(list1.map((el) => ++el)).toHaveValues()
})

xit('non-empty list', () => {
const list1 = List.create(1, 3, 5, 7)
expect(list1.map<number>((el) => ++el)).toHaveValues(2, 4, 6, 8)
expect(list1.map((el) => ++el)).toHaveValues(2, 4, 6, 8)
})
})

describe('folds (reduces) the given list from the left with a function', () => {
xit('empty list', () => {
const list1 = List.create()
expect(list1.foldl<number, number>((acc, el) => el * acc, 2)).toEqual(2)
const list1 = List.create<number>()
expect(list1.foldl((acc, el) => el * acc, 2)).toEqual(2)
})

xit('direction independent function applied to non-empty list', () => {
const list1 = List.create(1, 2, 3, 4)
expect(list1.foldl<number, number>((acc, el) => acc + el, 5)).toEqual(15)
expect(list1.foldl((acc, el) => acc + el, 5)).toEqual(15)
})

xit('direction dependent function applied to non-empty list', () => {
const list1 = List.create(1, 2, 3, 4)
expect(list1.foldl<number, number>((acc, el) => el / acc, 24)).toEqual(64)
expect(list1.foldl((acc, el) => el / acc, 24)).toEqual(64)
})
})

describe('folds (reduces) the given list from the right with a function', () => {
xit('empty list', () => {
const list1 = List.create()
expect(list1.foldr<number, number>((acc, el) => el * acc, 2)).toEqual(2)
const list1 = List.create<number>()
expect(list1.foldr((acc, el) => el * acc, 2)).toEqual(2)
})

xit('direction independent function applied to non-empty list', () => {
const list1 = List.create(1, 2, 3, 4)
expect(list1.foldr<number, number>((acc, el) => acc + el, 5)).toEqual(15)
expect(list1.foldr((acc, el) => acc + el, 5)).toEqual(15)
})

xit('direction dependent function applied to non-empty list', () => {
const list1 = List.create(1, 2, 3, 4)
expect(list1.foldr<number, number>((acc, el) => el / acc, 24)).toEqual(9)
expect(list1.foldr((acc, el) => el / acc, 24)).toEqual(9)
})
})

Expand Down

0 comments on commit 2ca3200

Please sign in to comment.