From 252e795a65a8f0d9043c319329635decdda793c4 Mon Sep 17 00:00:00 2001 From: Freywar Ulvnaudgari Date: Mon, 5 Aug 2024 20:37:25 +0300 Subject: [PATCH] List indexing --- src/list.ts | 15 ++++++++ test/list.spec.ts | 98 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 4 deletions(-) diff --git a/src/list.ts b/src/list.ts index 7924c5a..764858f 100644 --- a/src/list.ts +++ b/src/list.ts @@ -1,6 +1,7 @@ import { toNative as $$, L, P, _, fromNative as __, undef } from './core'; import { EQ, GT, LT, Ord, eq as eqc } from './ord'; import { Bool, False, True, and, iif, or } from './bool'; +import { Num } from 'src/num'; export type List = L<(z: R) => L<(f: L<(x: T) => L<(xs: List) => R>>) => R>>; @@ -99,6 +100,20 @@ export const all: L<(f: L<(x: T) => Bool>) => L<(xs: List) => Bo = _((f: L<(x: T) => Bool>) => _((xs: List) => xs._(True)._(_(x => _(xs => and._(f._(x))._(all._(f)._(xs))))))); +export const get: L<(i: Num) => L<(xs: List) => T>> + = _((i: Num) => + _((xs: List) => + xs._(undef)._(_((x: T) => _((xs: List) => i._(x)._(_(pi => get._(pi)._(xs)))))))); + +export const update: L<(f: L< (p: T) => T>) => L<(i: Num) => L<(xs: List) => List>>> + = _((f: L< (p: T) => T>) => + _((i: Num) => + _((xs: List) => + xs._(undef)._(_(x => _(xs => i._(cons._(f._(x))._(xs))._(_(pi => cons._(x)._(update._(f)._(pi)._(xs)))))))))); + +export const set: L<(v: T) => L<(i: Num) => L<(xs: List) => List>>> + = _((v: T) => update._(_(_ => v))); + export const fromArray: (xs: T[]) => List = xs => xs.length === 0 ? Nil : Cons._(xs[0])._(new L(() => fromArray(xs.slice(1)).value)); diff --git a/test/list.spec.ts b/test/list.spec.ts index 1297ebe..55ba529 100644 --- a/test/list.spec.ts +++ b/test/list.spec.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from '@jest/globals'; -import { fromNative as $$, L, _, toNative as __, undef } from '../src/core'; +import { toNative as $$, L, _, fromNative as __, undef } from '../src/core'; import { toNOrd as $o, NOrd } from '../src/ord'; import { toBoolean as $b, iif } from '../src/bool'; import { toNumber as $n, toNumber as $nn, Num, Succ, Zero, fromNumber as _n, fromNumber as _nn, cmp as cmpn, eq as eqn, even, odd, succ, sum } from '../src/num'; -import { toArray as $a, Cons, List, Nil, fromArray as _a, all, any, cmp, concat, cons, eq, filter, foldl, foldlz, foldr, foldrz, ge, gt, head, le, lt, map, tail } from '../src/list'; +import { toArray as $a, Cons, List, Nil, fromArray as _a, all, any, cmp, concat, cons, eq, filter, foldl, foldlz, foldr, foldrz, ge, get, gt, head, le, lt, map, set, tail, update } from '../src/list'; describe('List', () => { const iterate: (n: Num) => List = n => new L(() => Cons._(n)._(iterate(Succ._(n))).value); @@ -13,7 +13,7 @@ describe('List', () => { = xs => xs.length === 0 ? Nil : Cons._(_nn(xs[0]))._(new L(() => _na(xs.slice(1)).value)); const $na: (xs: List) => number[] - = xs => __(xs._($$([]))._(_(x => _(xs => $$([$nn(x), ...$na(xs)]))))); + = xs => $$(xs._(__([]))._(_(x => _(xs => __([$nn(x), ...$na(xs)]))))); describe('toArray', () => { it('converts []', () => { @@ -81,7 +81,7 @@ describe('List', () => { describe('head', () => { it('returns nothing from Nil', () => { - expect(() => __(head._(Nil))).toThrow(); + expect(() => $$(head._(Nil))).toThrow(); }); it('returns only item', () => { @@ -493,4 +493,94 @@ describe('List', () => { expect($b(all._(even)._(infinite))).toEqual(false); }); }); + + describe('get', () => { + it('returns nothing from Nil', () => { + expect(() => $n(get._(_n(0))._(Nil))).toThrow(); + }); + + it('returns nothing with out of bounds index', () => { + expect(() => $n(get._(_n(100))._(_na([0, 1, 2, 3])))).toThrow(); + }); + + it('[0, 1, 2, 3][0] is 0', () => { + expect($n(get._(_n(0))._(_na([0, 1, 2, 3])))).toBe(0); + }); + + it('[0, 1, 2, 3][1] is 1', () => { + expect($n(get._(_n(1))._(_na([0, 1, 2, 3])))).toBe(1); + }); + + it('[0, 1, 2, 3][2] is 2', () => { + expect($n(get._(_n(2))._(_na([0, 1, 2, 3])))).toBe(2); + }); + + it('[0, 1, 2, 3][3] get 3 is 3', () => { + expect($n(get._(_n(3))._(_na([0, 1, 2, 3])))).toBe(3); + }); + + it('handles infinite lists', () => { + expect($n(get._(_n(4))._(infinite))).toBe(4); + }); + }); + + describe('set', () => { + it('can not update Nil', () => { + expect(() => $na(set._(_n(10))._(_n(0))._(Nil))).toThrow(); + }); + + it('can not update out of bounds index', () => { + expect(() => $na(set._(_n(10))._(_n(100))._(_na([0, 1, 2, 3])))).toThrow(); + }); + + it('[0, 1, 2, 3][0] = 10 is [10, 1, 2, 3]', () => { + expect($na(set._(_n(10))._(_n(0))._(_na([0, 1, 2, 3])))).toEqual([10, 1, 2, 3]); + }); + + it('[0, 1, 2, 3][1] = 10 is [0, 10, 2, 3]', () => { + expect($na(set._(_n(10))._(_n(1))._(_na([0, 1, 2, 3])))).toEqual([0, 10, 2, 3]); + }); + + it('[0, 1, 2, 3][2] = 10 is [0, 1, 10, 3]', () => { + expect($na(set._(_n(10))._(_n(2))._(_na([0, 1, 2, 3])))).toEqual([0, 1, 10, 3]); + }); + + it('[0, 1, 2, 3][3] = 10 is [0, 1, 2, 10]', () => { + expect($na(set._(_n(10))._(_n(3))._(_na([0, 1, 2, 3])))).toEqual([0, 1, 2, 10]); + }); + + it('handles infinite lists', () => { + expect($n(get._(_n(4))._(set._(_n(10))._(_n(4))._(infinite)))).toBe(10); + }); + }); + + describe('update', () => { + it('can not update Nil', () => { + expect(() => $na(update._(succ)._(_n(0))._(Nil))).toThrow(); + }); + + it('can not update out of bounds index', () => { + expect(() => $na(update._(succ)._(_n(100))._(_na([0, 1, 2, 3])))).toThrow(); + }); + + it('[0, 1, 2, 3][0]++ is [10, 1, 2, 3]', () => { + expect($na(update._(succ)._(_n(0))._(_na([0, 1, 2, 3])))).toEqual([1, 1, 2, 3]); + }); + + it('[0, 1, 2, 3][1]++ is [0, 10, 2, 3]', () => { + expect($na(update._(succ)._(_n(1))._(_na([0, 1, 2, 3])))).toEqual([0, 2, 2, 3]); + }); + + it('[0, 1, 2, 3][2]++ is [0, 1, 10, 3]', () => { + expect($na(update._(succ)._(_n(2))._(_na([0, 1, 2, 3])))).toEqual([0, 1, 3, 3]); + }); + + it('[0, 1, 2, 3][3]++ is [0, 1, 2, 10]', () => { + expect($na(update._(succ)._(_n(3))._(_na([0, 1, 2, 3])))).toEqual([0, 1, 2, 4]); + }); + + it('handles infinite lists', () => { + expect($n(get._(_n(4))._(update._(succ)._(_n(4))._(infinite)))).toBe(5); + }); + }); });