Skip to content
This repository has been archived by the owner on Jan 9, 2024. It is now read-only.

Commit

Permalink
Merge pull request #20 from snatvb/bufix/either-chain
Browse files Browse the repository at this point in the history
Fix Either chain behaviour
  • Loading branch information
snatvb authored Mar 23, 2020
2 parents eb3775b + 6c6baa6 commit cefdcdb
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 23 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased] :bomb:

## :bulb: [0.5.1] - 2020-03-23

### :hammer: Fixed
- `Either.chain` was fixed. The behaviour will be correct.

## :bulb: [0.5.0] - 2020-03-20

### :gift: Added
Expand Down Expand Up @@ -65,7 +70,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Smoke test and really build to **Travis CI**.
- Labels of `npm`, `coverage`, `travis`.

[unreleased]: https://github.com/snatvb/monad-maniac/compare/v0.5.0...develop
[unreleased]: https://github.com/snatvb/monad-maniac/compare/v0.5.1...develop
[0.5.1]: https://github.com/snatvb/monad-maniac/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/snatvb/monad-maniac/compare/v0.4.0...v0.5.0
[0.4.0]: https://github.com/snatvb/monad-maniac/compare/v0.3.0...v0.4.0
[0.3.0]: https://github.com/snatvb/monad-maniac/compare/v0.2.0...v0.3.0
Expand Down
18 changes: 10 additions & 8 deletions src/either.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as helpers from './helpers'
import { Functor } from './interfaces'
import * as Maybe from './maybe'
import { Nullable } from './types'
import { Functor } from './interfaces'

/** Mather type for caseOf */
export type CaseOf<L, R, U> = {
Expand Down Expand Up @@ -83,7 +83,7 @@ export interface Either<L, R> extends Functor<R> {
* ```
* @param f Function to apply for Right value
*/
chain<U>(f: (value: R) => U): U | Either<L, U>
chain<U>(f: (value: R) => Either<L, U>): Either<L, U>
/**
* Apply predicate function to value in container.
* If the function returns not `true` then value from
Expand Down Expand Up @@ -433,15 +433,17 @@ export function map<L, R, U>(f: (value: R) => U, either?: Either<L, R>): Either<
* const result: Either.Shape<string, string> = typeof name === 'string'
* ? new Either.Right(name)
* : new Either.Left('Server error')
* const greeting = Either.chain((name) => `Welcome, ${name}!`, result) // 'Welcome, Jake' or 'Server error'
* const greeting = Either.chain(
* (name: string) => Either.right(`Welcome, ${name}!`)
* ), result).get() // 'Welcome, Jake' or 'Server error'
* ```
* */
export function chain<L, R, U>(f: (value: R) => U, either: Either<L, R>): Either<L, U> | U
export function chain<L, R, U>(f: (value: R) => Either<L, U>, either: Either<L, R>): Either<L, U>
/**
* Just curried `chain`.
*/
export function chain<L, R, U>(f: (value: R) => U): (either: Either<L, R>) => Either<L, U> | U
export function chain<L, R, U>(f: (value: R) => U, either?: Either<L, R>): Either<L, U> | U | ((either: Either<L, R>) => Either<L, U> | U) {
export function chain<L, R, U>(f: (value: R) => Either<L, U>): (either: Either<L, R>) => Either<L, U>
export function chain<L, R, U>(f: (value: R) => Either<L, U>, either?: Either<L, R>): Either<L, U> | ((either: Either<L, R>) => Either<L, U>) {
const op = (either: Either<L, R>) => either.chain(f)
return helpers.curry1(op, either)
}
Expand Down Expand Up @@ -580,7 +582,7 @@ export class Right<L ,R> implements Either<L ,R> {
return this.value
}

chain<U>(f: (value: R) => U): U | Either<L, U> {
chain<U>(f: (value: R) => Either<L, U>): Either<L, U> {
return f(this.value)
}

Expand Down Expand Up @@ -628,7 +630,7 @@ export class Left<L, R> implements Either<L, R> {
return f(this.value)
}

chain<U>(_f: (value: R) => U): U | Either<L, U> {
chain<U>(_f: (value: R) => Either<L, U>): Either<L, U> {
return new Left<L, U>(this.value)
}

Expand Down
42 changes: 28 additions & 14 deletions tests/either.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Either } from '../src'

const double = (x: number): number => x * 2
const chainDouble = (x: number): Either.Shape<string, number> => Either.right(x * 2)
const greetChain = (name: string): Either.Shape<string, string> => Either.right<string, string>(`Welcome, ${name}!`)

describe('Either pure functions', () => {
describe('of', () => {
Expand Down Expand Up @@ -84,19 +86,19 @@ describe('Either pure functions', () => {
it('direct call', () => {
const left: Either.Shape<string, number> = new Either.Left('Server error')
const right: Either.Shape<string, number> = new Either.Right(150)
const leftResult = Either.chain(double, left)
const leftResult = Either.chain(chainDouble, left)

expect(leftResult instanceof Either.Left).toBe(true)
expect(Either.chain(double, right)).toBe(300)
expect(Either.chain(chainDouble, right).get()).toBe(300)
})

it('carried', () => {
const left: Either.Shape<string, number> = new Either.Left('Server error')
const right: Either.Shape<string, number> = new Either.Right(150)
const leftResult = Either.chain(double)(left)
const leftResult = Either.chain(chainDouble)(left)

expect(leftResult instanceof Either.Left).toBe(true)
expect(Either.chain(double)(right)).toBe(300)
expect(Either.chain(chainDouble)(right).get()).toBe(300)
})
})

Expand Down Expand Up @@ -280,8 +282,8 @@ describe('Either: Left & Right', () => {
const left: Either.Shape<string, number> = new Either.Left('Server error')
const right: Either.Shape<string, number> = new Either.Right(150)

expect(left.chain(double) instanceof Either.Left).toBe(true)
expect(right.chain(double)).toBe(300)
expect(left.chain(chainDouble).isLeft()).toBe(true)
expect(right.chain(chainDouble).isRight()).toBe(true)
})

it('getOrElse', () => {
Expand Down Expand Up @@ -344,10 +346,10 @@ describe('Either: Left & Right', () => {
describe('Cases from docs', () => {
it('map', () => {
const divide = (dividend: number) => (divider: number): Either.Shape<string, number> => {
if (divider === 0) {
return Either.left('Divider is zero!')
}
return Either.right(dividend / divider)
if (divider === 0) {
return Either.left('Divider is zero!')
}
return Either.right(dividend / divider)
}

const resultNormal = divide(10)(5).map(double).get() // 4
Expand All @@ -358,10 +360,10 @@ describe('Cases from docs', () => {

it('chain', () => {
const divide = (dividend: number) => (divider: number): Either.Shape<string, number> => {
if (divider === 0) {
return Either.left('Divider is zero!')
}
return Either.right(dividend / divider)
if (divider === 0) {
return Either.left('Divider is zero!')
}
return Either.right(dividend / divider)
}

const nonZeroMultiply = (multiplicand: number) => (factor: number): Either.Shape<string, number> => {
Expand Down Expand Up @@ -471,4 +473,16 @@ describe('Cases from docs', () => {
expect(resultRight.toString()).toBe('Just(150)')
expect(resultRightVoid.toString()).toBe('Nothing()')
})

// ========= DOC TESTS =========
it('Chain from doc', () => {

const greeting = Either.chain(greetChain, Either.right('Jake')).get()
expect(greeting).toBe('Welcome, Jake!')

// Server error

const serverError = Either.chain(greetChain, Either.left('Server error')).get()
expect(serverError).toBe('Server error')
})
})

0 comments on commit cefdcdb

Please sign in to comment.