Skip to content

Commit

Permalink
Merge pull request #8 from web-pacotes/7-feat-foldright-foldleft
Browse files Browse the repository at this point in the history
feat(monad): implement leftMap and leftRight
  • Loading branch information
freitzzz authored May 21, 2024
2 parents 9c3d2bb + d3e8488 commit d90f2a8
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 8 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions src/error/call.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import {
safeAsyncThrowCall,
safeThrowCall
} from './call';
import { fold, isRight, Right } from '../monad';
import { Either, fold, isRight, Right } from '../monad';
import { isTypedError, TypedError } from './typed';
import { UnknownError } from './unknown';

describe('call', () => {
describe('safeThrowCall', () => {
test('returns callback result if no error is thrown', () => {
const callback = () => Right(2 + 2);
const callback = () => Right(2 + 2) satisfies Either<TypedError, number>;

const result = safeThrowCall(callback);
const isRightHanded = isRight(result);
Expand Down Expand Up @@ -58,7 +58,8 @@ describe('call', () => {

describe('safeAsyncThrowCall', () => {
test('returns callback result if no error is thrown', async () => {
const callback = async () => Right(2 + 2);
const callback = async () =>
Right(2 + 2) satisfies Either<TypedError, unknown>;

const result = await safeAsyncThrowCall(callback);
const isRightHanded = isRight(result);
Expand Down
51 changes: 50 additions & 1 deletion src/monad/either.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import { describe, expect, test } from '@jest/globals';
import { fold, isLeft, isRight, Left, Right } from './either';
import {
Either,
fold,
isLeft,
isRight,
Left,
leftMap,
Right,
rightMap
} from './either';

describe('either', () => {
describe('isLeft', () => {
Expand Down Expand Up @@ -65,4 +74,44 @@ describe('either', () => {
expect(result).toBe(value - 1);
});
});

describe('leftMap', () => {
test('computes left callback if monad is left-handed', () => {
const value = 0;
const monad = Left(value);

const result = leftMap(monad, (l) => l + 1);

expect(result).toStrictEqual(Left(value + 1));
});

test('does not compute left callback if monad is right-handed', () => {
const value = 0;
const monad = Right(value) satisfies Either<number, number>;

const result = leftMap(monad, (l) => l + 1);

expect(result).toStrictEqual(Right(value));
});
});

describe('rightMap', () => {
test('computes right callback if monad is right-handed', () => {
const value = 0;
const monad = Right(value);

const result = rightMap(monad, (r) => r + 1);

expect(result).toStrictEqual(Right(value + 1));
});

test('does not compute right callback if monad is left-handed', () => {
const value = 0;
const monad = Left(value) satisfies Either<number, number>;

const result = rightMap(monad, (l) => l + 1);

expect(result).toStrictEqual(Left(value));
});
});
});
27 changes: 25 additions & 2 deletions src/monad/either.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export type Either<L, R> = Left<L> | Right<R>;
*
* @param value - the value that represents the left hand
*/
export const Left = <L, R>(value: L) => {
export const Left = <L, R>(value: L): Either<L, R> => {
return {
tag: 'left',
left: value
Expand All @@ -36,7 +36,7 @@ export const Left = <L, R>(value: L) => {
*
* @param value - the value that represents the right hand
*/
export const Right = <L, R>(value: R) => {
export const Right = <L, R>(value: R): Either<L, R> => {
return {
tag: 'right',
right: value
Expand Down Expand Up @@ -79,3 +79,26 @@ export const fold = <L, R, F>(
return right(value.right);
}
};

/**
* Transforms an [Either] monad by mapping the left hand to a new value, if left-handed.
*
* @param value - the monad value to fold
* @param left - callback for mapping the left-hand
* @returns - an [Either] monad in which the left callback is applied to the left hand.
*/
export const leftMap = <L1, L2, R>(value: Either<L1, R>, left: (l: L1) => L2) =>
(isLeft(value) ? Left(left(value.left)) : value) satisfies Either<L2, R>;

/**
* Transforms an [Either] monad by mapping the right hand to a new value, if right-handed.
*
* @param value - the monad value to fold
* @param left - callback for mapping the right-hand
* @returns - an [Either] monad in which the right callback is applied to the right hand.
*/
export const rightMap = <L, R1, R2>(
value: Either<L, R1>,
right: (r: R1) => R2
) =>
(isRight(value) ? Right(right(value.right)) : value) satisfies Either<L, R2>;

0 comments on commit d90f2a8

Please sign in to comment.