Skip to content

Commit

Permalink
issue-#43,#61 - Progress on types (adding Slice type, simplifying imp…
Browse files Browse the repository at this point in the history
…lementaitons and types)and updates to tests towards 'green' tests.
  • Loading branch information
elycruz committed Aug 28, 2022
1 parent 45147ba commit e31d52e
Show file tree
Hide file tree
Showing 27 changed files with 173 additions and 157 deletions.
3 changes: 2 additions & 1 deletion packages/fjl/src/list/concat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ export const
/**
* Concatenates all the elements of a container of lists.
*/
concat = <T, TS extends Slice<T>>(xs: TS[]): TS => append(...xs) as TS
concat = <T, TS extends Slice<T>>(xs: TS[]): TS =>
append(...xs) as TS
;
6 changes: 3 additions & 3 deletions packages/fjl/src/list/foldr1.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {unconsr} from "./unconsr";
import {reduceRight} from "./utils/reduceRight";
import {ReduceOp, Slice} from "../types";
import {unconsr} from "./unconsr";

export const

/**
* A variant of `foldr` except that this one doesn't require the starting point/value. The starting value passed in
* is the first item, from the right (end of given array).
* is the first item, from the right (end of given list).
*/
foldr1 = <T>(op: ReduceOp<T, Slice<T>, T>, xs: Slice<T>): T => {
const parts = unconsr(xs) as [Slice<T>, T];
// If no pars return, else pass tail and head, of `unconsr` array.
// If no parts return, else pass tail and head, of `unconsr` array to `reduceRight` func..
return !parts ? undefined : reduceRight(op, parts[1], parts[0]);
},

Expand Down
2 changes: 1 addition & 1 deletion packages/fjl/src/list/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ import {equal} from "../boolean";
* group("Mississippi".slice(0)) === [["M"], ["i"], ["s", "s"], ["i"], ["s", "s"], ["i"], ["p", "p"], "i"]
* ```
*/
export const group = <T, TS extends T[]>(xs: TS): T[][] => groupBy(equal, xs);
export const group = <T>(xs: T[]): T[][] => groupBy(equal, xs);
9 changes: 3 additions & 6 deletions packages/fjl/src/list/groupBy.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {BinaryPred} from "../types";
import {BinaryPred, Slice} from "../types";

export const

Expand All @@ -11,24 +11,21 @@ export const
* ```
*/
groupBy = <T, TS extends T[]>(equalityOp: BinaryPred<T>, xs: TS): T[][] => {
// Bail if empty list
if (!xs) return [];

const limit = xs.length;

// Bail if empty list
if (!limit) return [[]];

// Groupings
const groups: T[][] = [];

// Initialize variables for tracking
let ind = 1,
prevItem = xs[0] as T,
let prevItem = xs[0] as T,
group: T[] = [prevItem];

// Group remainder of items
for (; ind < limit; ind += 1) {
for (let ind = 1; ind < limit; ind += 1) {
const x = xs[ind] as T;

// If equality check passed group item, and continue to next
Expand Down
20 changes: 11 additions & 9 deletions packages/fjl/src/list/isInfixOf.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {Slice} from "../types";

export const

/**
* Checks if list `xs1` is an infix of list `xs2`
*/
isInfixOf = <T, TS extends T[]>(xs1: TS, xs2: TS): boolean => {
isInfixOf = <T>(xs1: Slice<T>, xs2: Slice<T>): boolean => {
const limit1 = xs1.length,
limit2 = xs2.length;
if (limit2 < limit1 || !limit1 || !limit2) {
return false;
}

if (limit2 < limit1 || !limit1 || !limit2) return false;

let ind1,
foundLen,
ind = 0;
for (; ind < limit2; ind += 1) {
foundLen;

for (let ind = 0; ind < limit2; ind += 1) {
foundLen = 0;
for (ind1 = 0; ind1 < limit1; ind1 += 1) {
if (xs2[ind1 + ind] === xs1[ind1]) {
Expand All @@ -26,7 +28,7 @@ export const
return false;
},

$isInfixOf = <T, TS extends T[]>(xs1: TS) =>
(xs2: TS): boolean => isInfixOf(xs1, xs2)
$isInfixOf = <T>(xs1: Slice<T>) =>
(xs2: Slice<T>): boolean => isInfixOf(xs1, xs2)

;
2 changes: 2 additions & 0 deletions packages/fjl/src/list/isSubsequenceOf.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {$equal} from "../boolean";
import {findIndex} from "./findIndex";
import {Slice} from "../types";
import {isset} from "../object";

export const
/**
* Checks if list `xs1` is a sub-sequence of list `xs2`
*/
isSubsequenceOf = <T>(xs1: Slice<T>, xs2: Slice<T>): boolean => {
if (!isset(xs1) || !isset(xs2)) return false;
const len = Math.pow(2, xs2.length),
lenXs1 = xs1.length;
let foundLen,
Expand Down
3 changes: 2 additions & 1 deletion packages/fjl/src/list/last.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {lastIndex} from './utils';
import {Slice} from "../types";

/**
* Returns last item of list.
*/
export const last = <T>(xs: T[]): T | undefined => xs[lastIndex(xs)];
export const last = <T>(xs: Slice<T>): T | undefined => xs[lastIndex(xs)];
4 changes: 3 additions & 1 deletion packages/fjl/src/list/length.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export const length = (x: { readonly length?: number }) => x.length;
import {isset} from "../object";

export const length = (x: { readonly length?: number }) => !isset(x) ? undefined : x.length;
12 changes: 7 additions & 5 deletions packages/fjl/src/list/permutations.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {swap} from "./utils";
import {isEven} from "../number";

/**
* Returns a list of permutations for passed in list.
Expand All @@ -10,22 +11,23 @@ export const permutations = <T>(xs: T[]): T[][] => {

if (!limit || limit === 1) return [xs];

const c = [].fill(0, 0, limit);
const c = Array(limit).fill(0, 0, limit);
let list: T[] = xs.slice(0),
i = 0;
i = 0

const out = [list] as T[][];

for (; i < limit; i++) {
while (i < limit) {
if (c[i] < i) {
// `(i & 0) === 1` checks if `i` is even or not
list = swap(((i & 0) === 1 ? 0 : c[i]), i, list);
// `(i & 1) === 0` checks if `i` is even or not
list = swap((isEven(i) ? 0 : c[i]), i, list);
out.push(list);
c[i] += 1;
i = 0;
continue;
}
c[i] = 0;
i += 1;
}

return out;
Expand Down
14 changes: 7 additions & 7 deletions packages/fjl/src/list/tails.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {length} from "./length";
import {slice} from "../platform/slice";
import {Slice} from "../types";
import {of} from "../object";

export const

Expand All @@ -9,14 +10,13 @@ export const
* shallowEquals(tails('abc'), ['abc', 'bc', 'c',''])
* ```
*/
tails = <T>(xs: T[]): T[] => {
let limit = length(xs),
ind = 0,
agg: [any[]] | any[] = [];
tails = <T, TS extends Slice<T>>(xs: TS): TS[] => {
const limit = xs.length;
if (!limit) {
return [];
return [of(xs)];
}
for (; ind <= limit; ind += 1) {
const agg: TS[] = [];
for (let ind = 0; ind <= limit; ind += 1) {
agg.push(slice(ind, limit, xs));
}
return agg;
Expand Down
10 changes: 5 additions & 5 deletions packages/fjl/src/list/takeWhile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,23 @@ import {reduceUntil} from "./utils";
import {isString} from "../object/is";
import {of} from "../object/of";
import {push} from "./push";
import {TernaryPred} from "../types";
import {Slice, TernaryPred} from "../types";

export const

/**
* Gives an list with passed elements while predicate was true.
*/
takeWhile = <T>(pred: TernaryPred, xs: T[]): T[] =>
takeWhile = <T>(pred: TernaryPred, xs: Slice<T>): Slice<T> =>
reduceUntil(
negateF3(pred),
isString(xs) ?
(agg, x) => ((agg as unknown as string) + x) as unknown as T[]:
(agg, x): T[] => push(x, agg as T[]),
(agg, x) => (agg + x) :
(agg, x): T[] => push(x, agg),
of(xs),
xs
),

$takeWhile = <T>(pred: TernaryPred) =>
(xs: T[]): T[] =>
(xs: Slice<T>): Slice<T> =>
takeWhile(pred, xs);
10 changes: 5 additions & 5 deletions packages/fjl/src/list/unionBy.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {foldl} from "./foldl";
import {any} from "./any";
import {sliceCopy} from "./utils/sliceCopy";
import {BinaryPred} from "../types";
import {BinaryPred, Slice} from "../types";

const getFoldOpForArray = <T>(pred: BinaryPred<T, T>) => (agg: T[], b: T): T[] => {
const alreadyAdded = any((a: T) => pred(a, b), agg);
Expand All @@ -19,12 +19,12 @@ export const
/**
* Returns the union on elements matching boolean check passed in.
*/
unionBy = <T>(pred: BinaryPred<T, T>, xs1: T[], xs2: T[]): T[] => {
unionBy = <T>(pred: BinaryPred<T, T>, xs1: Slice<T>, xs2: Slice<T>): Slice<T> => {
const foldOp = typeof xs1 === 'string' ? getFoldOpForString(pred) : getFoldOpForArray(pred);
return foldl(foldOp, sliceCopy(xs1) as T[], xs2) as T[];
return foldl(foldOp, sliceCopy(xs1), xs2);
},

$unionBy = <T>(pred: BinaryPred<T, T>) =>
(xs1: T[]) =>
(xs2: T[]): T[] =>
(xs1: Slice<T>) =>
(xs2: Slice<T>): Slice<T> =>
unionBy(pred, xs1, xs2);
12 changes: 4 additions & 8 deletions packages/fjl/src/list/unzip.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import {foldl} from "./foldl";

export const

/**
* unzip transforms a list of pairs into a list of first components and a list of second components.
* @haskellType `unzip :: [(a, b)] -> ([a], [b])`
* unzip transforms a list of pairs into a tuple of lists - first list contains first components and a second contains second ones.
*/
unzip = <T1, T2>(xss: [T1, T2][]): [T1[], T2[]] => {
if (!xss) {
throw new Error(`\`unzip\` expects a value. Received ${JSON.stringify(xss)}`);
}
return foldl((agg, item: [T1, T2]) => {
unzip = <T1, T2>(xss: [T1, T2][]): [T1[], T2[]] =>
foldl((agg, item: [T1, T2]) => {
if (item.length) {
agg[0].push(item[0]);
agg[1].push(item[1]);
}
return agg;
}, [[], []], xss);
};
15 changes: 10 additions & 5 deletions packages/fjl/src/list/utils/reduce.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
import {reduceUntil} from "./reduceUntil";
import {alwaysFalse} from "../../boolean/alwaysFalse";
import {ReduceOp} from "../../types";

export const

/**
* Reduces a "number indexable" by given reduction function (same as [].reduce but also for strings/arbitrary "number indexable" objects/etc.).
*/
reduce = (op: ReduceOp, agg, xs) =>
reduceUntil(alwaysFalse, op, agg, xs),
reduce = (op: ReduceOp, agg, xs) => {
const limit = xs.length;
if (!limit) return agg;
let result = agg;
for (let ind = 0; ind < limit; ind++) {
result = op(result, xs[ind], ind, xs);
}
return result;
},

/**
* Curried `reduce` combinator.
*/
$reduce = (op: ReduceOp) => agg => xs =>
reduceUntil(alwaysFalse, op, agg, xs)
reduce(op, agg, xs)

;
13 changes: 10 additions & 3 deletions packages/fjl/src/list/utils/reduceRight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,19 @@ export const
op: ReduceOp<T, Slice<T>, RetT>,
agg: RetT,
xs: Slice<T>
): RetT =>
reduceUntilRight(alwaysFalse, op, agg, xs),
): RetT => {
const limit = xs.length;
if (!limit) return agg;
let result = agg;
for (let ind = limit - 1; ind >= 0; ind--) {
result = op(result, xs[ind], ind, xs);
}
return result;
},

$reduceRight = <T, RetT>(op: ReduceOp<T, Slice<T>, RetT>) =>
(agg: RetT) =>
(xs: Slice<T>): RetT =>
reduceUntilRight(alwaysFalse, op, agg, xs)
reduceRight(op, agg, xs)

;
2 changes: 1 addition & 1 deletion packages/fjl/src/number/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const isEven = (x: number): boolean => (x & 0) === 1,
export const isEven = (x: number): boolean => !(x & 1),

isOdd = (x: number) => (x & 1) === 1,

Expand Down
6 changes: 1 addition & 5 deletions packages/fjl/src/types/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,12 @@ export type ForEachOp<T, FtrT> = (x: T, i?: number | string, xs?: FtrT) => void

export type MapOp<T, Ind, FtrT, RetT> = (x: T, i?: Ind, xs?: FtrT) => RetT;

export type ReduceOp<T=any, FtrT=any, ZeroT=any> = (agg: ZeroT, x: T, i?: number | keyof FtrT, xs?: FtrT) => ZeroT;
export type ReduceOp<T=any, Fnctr=any, ZeroT=any> = (agg: ZeroT, x: T, i?: number | keyof Fnctr, xs?: Fnctr) => ZeroT;

export type MapAccumOp<A = any, B = any, C = any, Ind = number | string, Functor = Slice<B>> =
(agg?: A, x?: B, i?: Ind, xs?: Functor) => [A, C];

export type PredForIndexable<T = any> = IndexableTernaryPred<T, number | string, Indexable<T>>;
export type PredForNumIndexable<T = any> = TernaryPred<T, number, NumberIndexable<T>>;

export type PredForArray<T = any> = TernaryPred<T, number, T[]>;
export type PredForArrayType<T, TS extends ArrayType<T>> = TernaryPred<T, number, TS>;

export type PredForSlice<T = any, T2 extends Slice<T> = Slice<T>> =
ArrayTernaryPred<T, number | string, T2>;
Expand Down
2 changes: 1 addition & 1 deletion packages/fjl/tests/list/test-concat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ describe('#concat', () => {
arg2 = ['abc', 'def', 'ghi'],
arg3 = [vowelsArray, vowelsArray, vowelsArray];
(<Slice<string>[][][]>[
[[], []],
[[], undefined],
[['', '', ''], ''],
[[[], [], []], []],
[arg1, [].concat(...arg1)],
Expand Down
4 changes: 2 additions & 2 deletions packages/fjl/tests/list/test-cycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ describe('#cycle', () => {
(<[Parameters<typeof cycle>, ReturnType<typeof cycle>][]>[
[[5, 'x'], 'xxxxx'],
[[5, ['x']], 'xxxxx'.split('').map(c => [c])],
[[5, ''], [].fill('', 0, 5)],
[[5, []], [].fill([], 0, 5)],
[[5, ''], Array(5).fill('', 0, 5)],
[[5, []], Array(5).fill([], 0, 5)],
])
.forEach(([args, expected]) => {
it(`cycle(${args.map(x => stringify(x)).join(', ')}) === ` +
Expand Down
Loading

0 comments on commit e31d52e

Please sign in to comment.