diff --git a/docs/fantas-eel-and-specification/10.ts b/docs/fantas-eel-and-specification/10.ts index b1ebe807e..18805ff69 100644 --- a/docs/fantas-eel-and-specification/10.ts +++ b/docs/fantas-eel-and-specification/10.ts @@ -11,6 +11,6 @@ import { Plus } from '../../src/Plus' import { Monoid } from '../../src/Monoid' export const getMonoid = (plus: Plus) => (): Monoid> => ({ - concat: plus.alt, + concat: x => y => plus.alt(x, y), empty: plus.zero }) diff --git a/docs/fantas-eel-and-specification/13.ts b/docs/fantas-eel-and-specification/13.ts index 2e368859b..2ce353665 100644 --- a/docs/fantas-eel-and-specification/13.ts +++ b/docs/fantas-eel-and-specification/13.ts @@ -57,7 +57,7 @@ export const sqrt = (x: number): either.Either => console.log( either - .right(16) + .right(16) .chain(sqrt) .chain(sqrt) ) @@ -65,7 +65,7 @@ console.log( console.log( either - .right(81) + .right(81) .chain(sqrt) .map(x => -x) .chain(sqrt) @@ -73,7 +73,7 @@ console.log( ) // => left("Hey, no!") -console.log(either.left('eep').chain(sqrt)) +console.log(either.left('eep').chain(sqrt)) // => left("eep") // @@ -90,7 +90,9 @@ const flights = { JFK: ['LAX', 'DEN'] } -const whereNext = (x: keyof typeof flights): Array => flights[x] || [] +type FLIGHT = keyof typeof flights + +const whereNext = (x: FLIGHT): Array => (flights[x] || []) as Array console.log(array.chain(whereNext, array.chain(whereNext, whereNext('LAX')))) // => [ 'JFK', 'ATL', 'ATL', 'ORD', 'DFW', 'JFK', 'ATL' ] diff --git a/docs/fantas-eel-and-specification/17.ts b/docs/fantas-eel-and-specification/17.ts index 33941012b..60f68ba8f 100644 --- a/docs/fantas-eel-and-specification/17.ts +++ b/docs/fantas-eel-and-specification/17.ts @@ -50,7 +50,7 @@ export const isSurvivor = (game: Game): boolean => { export const fromBoard = (board: Board): Game => { return new Store(pointer => { const [x, y] = pointer.value - return getBoardValue(board, x, y).getOrElse(() => false) + return getBoardValue(board, x, y).getOrElseValue(false) }, new Tuple([0, 0])) } diff --git a/docs/fantas-eel-and-specification/18.ts b/docs/fantas-eel-and-specification/18.ts index ab17bde52..78b4e4591 100644 --- a/docs/fantas-eel-and-specification/18.ts +++ b/docs/fantas-eel-and-specification/18.ts @@ -35,7 +35,9 @@ export class Costar { import * as array from '../../src/Array' // Takes a list of ints to the sum -export const sum = new Costar<'Array', number, number>(array, (xs: Array) => xs.reduce((acc, x) => acc + x, 0)) +export const sum = new Costar<'Array', number, number>(array, (xs: HKT<'Array', number>) => + (xs as Array).reduce((acc, x) => acc + x, 0) +) // Make every element 1, then sum them! export const length = sum.promap(() => 1, x => x) diff --git a/docs/fantas-eel-and-specification/8.ts b/docs/fantas-eel-and-specification/8.ts index d876ce4d5..4c4a548bc 100644 --- a/docs/fantas-eel-and-specification/8.ts +++ b/docs/fantas-eel-and-specification/8.ts @@ -47,9 +47,9 @@ console.log(option.none.ap(option.none)) // => none import * as either from '../../src/Either' console.log(either.right(2).ap(either.right((x: number) => -x))) // => right(-2) -console.log(either.left('halp').ap(either.right((x: number) => -x))) // => left("halp") -console.log(either.right(2).ap(either.left('eek'))) // => left("eek") -console.log(either.left('halp').ap(either.left('eek'))) // => left("eek") +console.log(either.left('halp').ap(either.right((x: number) => -x))) // => left("halp") +console.log(either.right(2).ap(either.left number>('eek'))) // => left("eek") +console.log(either.left('halp').ap(either.left number>('eek'))) // => left("eek") // // Task diff --git a/docs/fantas-eel-and-specification/9.ts b/docs/fantas-eel-and-specification/9.ts index d6d95206c..6652cdfd8 100644 --- a/docs/fantas-eel-and-specification/9.ts +++ b/docs/fantas-eel-and-specification/9.ts @@ -12,7 +12,8 @@ export const append = (y: A) => (xs: Array) => xs.concat([y]) export function insideOut(F: Applicative): (xs: Array>) => HKTAs> export function insideOut(F: Applicative): (xs: Array>) => HKT> export function insideOut(F: Applicative): (xs: Array>) => HKT> { - return (xs: Array>) => xs.reduce((acc, x) => liftA2(F), Array>(append)(x)(acc), F.of([])) + return (xs: Array>) => + xs.reduce((acc, x) => liftA2(F), Array>(append)(x)(acc), F.of([])) } import * as option from '../../src/Option' @@ -37,10 +38,13 @@ import { getArrayMonoid } from '../../src/Monoid' const monoidArrayNumber = getArrayMonoid() // Usual implementation: -console.log(option.concat(monoidArrayNumber)(option.some([2]))(option.some([3]))) // => some([2, 3]) -console.log(option.concat(monoidArrayNumber)(option.some([2]))(option.none)) // => some([2]) -console.log(option.concat(monoidArrayNumber)(option.none)(option.some([3]))) // => some([3]) -console.log(option.concat(monoidArrayNumber)(option.none)(option.none)) // => none + +const { concat } = option.getSemigroup(monoidArrayNumber) + +console.log(concat(option.some([2]))(option.some([3]))) // => some([2, 3]) +console.log(concat(option.some([2]))(option.none)) // => some([2]) +console.log(concat(option.none)(option.some([3]))) // => some([3]) +console.log(concat(option.none)(option.none)) // => none // With the above implementation diff --git a/examples/ArrayOption.ts b/examples/ArrayOption.ts index d93b22a0c..fe611d0b0 100644 --- a/examples/ArrayOption.ts +++ b/examples/ArrayOption.ts @@ -32,8 +32,8 @@ export class ArrayOption implements FantasyMonad { chain(f: (a: A) => ArrayOption): ArrayOption { return new ArrayOption(optionTArray.chain(a => f(a).value, this.value)) } - getOrElse(f: Lazy): Array { - return optionT.getOrElse(array)(f)(this.value) + getOrElseValue(a: A): Array { + return optionT.getOrElseValue(array)(a)(this.value) } fold(none: Lazy, some: (a: A) => R): Array { return optionT.fold(array)(none, some, this.value) diff --git a/examples/EitherOption.ts b/examples/EitherOption.ts index 7420cd11a..ab3cb75ce 100644 --- a/examples/EitherOption.ts +++ b/examples/EitherOption.ts @@ -33,8 +33,8 @@ export class EitherOption implements FantasyMonad { chain(f: (a: A) => EitherOption): EitherOption { return new EitherOption(optionTEither.chain(a => f(a).value, this.value)) } - getOrElse(f: Lazy): either.Either { - return optionT.getOrElse(either)(f)(this.value) + getOrElseValue(a: A): either.Either { + return optionT.getOrElseValue(either)(a)(this.value) } fold(none: Lazy, some: (a: A) => R): either.Either { return optionT.fold(either)(none, some, this.value) diff --git a/examples/Moore.ts b/examples/Moore.ts index 298e44f13..30ed6839b 100644 --- a/examples/Moore.ts +++ b/examples/Moore.ts @@ -67,8 +67,7 @@ export const extract = (fa: Moore): A => fa.extract() export const extend = (f: (fa: Moore) => B, fa: Moore): Moore => fa.extend(f) -export const promap = (f: (a: A) => B, g: (c: C) => D) => (fla: Moore): Moore => - fla.promap(f, g) +export const promap = (f: (a: A) => B, g: (c: C) => D, fla: Moore): Moore => fla.promap(f, g) /** Construct a Moore machine from a state valuation and transition function */ export const unfoldMoore = (f: (s: S) => [A, (l: L) => S]) => (s: S): Moore => { diff --git a/examples/ReaderIO.ts b/examples/ReaderIO.ts index 987529099..8ab24304c 100644 --- a/examples/ReaderIO.ts +++ b/examples/ReaderIO.ts @@ -18,21 +18,21 @@ export class ReaderIO implements FantasyMonad { readonly _A: A readonly _L: E readonly _URI: URI - constructor(readonly value: (e: E) => io.IO) {} + constructor(readonly run: (e: E) => io.IO) {} map(f: (a: A) => B): ReaderIO { - return new ReaderIO(readerTIO.map(f, this.value)) + return new ReaderIO(readerTIO.map(f, this.run)) } of(b: B): ReaderIO { return of(b) } ap(fab: ReaderIO B>): ReaderIO { - return new ReaderIO(readerTIO.ap(fab.value, this.value)) + return new ReaderIO(readerTIO.ap(fab.run, this.run)) } ap_(this: ReaderIO C>, fb: ReaderIO): ReaderIO { return fb.ap(this) } chain(f: (a: A) => ReaderIO): ReaderIO { - return new ReaderIO(readerTIO.chain(a => f(a).value, this.value)) + return new ReaderIO(readerTIO.chain(a => f(a).run, this.run)) } } @@ -48,6 +48,8 @@ export const ask = (e: E): ReaderIO => new ReaderIO(readerT.ask(io)()) export const asks = (f: (e: E) => A): ReaderIO => new ReaderIO(readerT.asks(io)(f)) +export const local = (f: (e: E) => E) => (fa: ReaderIO): ReaderIO => new ReaderIO(e => fa.run(f(e))) + export const readerIO: Monad = { URI, map, diff --git a/examples/ReaderTaskEither.ts b/examples/ReaderTaskEither.ts new file mode 100644 index 000000000..c64b2eafb --- /dev/null +++ b/examples/ReaderTaskEither.ts @@ -0,0 +1,82 @@ +import * as readerT from 'fp-ts/lib/ReaderT' +import * as taskEither from 'fp-ts/lib/TaskEither' +import { TaskEither } from 'fp-ts/lib/TaskEither' +import { Monad, FantasyMonad } from 'fp-ts/lib/Monad' +import { Task } from 'fp-ts/lib/Task' +import { Either } from 'fp-ts/lib/Either' + +const readerTTaskEither = readerT.getReaderT(taskEither) + +declare module 'fp-ts/lib/HKT' { + interface URI2HKT3 { + ReaderTaskEither: ReaderTaskEither + } +} + +export const URI = 'ReaderTaskEither' + +export type URI = typeof URI + +export class ReaderTaskEither implements FantasyMonad { + readonly _A: A + readonly _L: L + readonly _U: E + readonly _URI: URI + constructor(readonly run: (e: E) => TaskEither) {} + map(f: (a: A) => B): ReaderTaskEither { + return new ReaderTaskEither(readerTTaskEither.map(f, this.run)) + } + of(b: B): ReaderTaskEither { + return of(b) + } + ap(fab: ReaderTaskEither B>): ReaderTaskEither { + return new ReaderTaskEither(readerTTaskEither.ap(fab.run, this.run)) + } + ap_(this: ReaderTaskEither C>, fb: ReaderTaskEither): ReaderTaskEither { + return fb.ap(this) + } + chain(f: (a: A) => ReaderTaskEither): ReaderTaskEither { + return new ReaderTaskEither(readerTTaskEither.chain(a => f(a).run, this.run)) + } +} + +export const map = (f: (a: A) => B, fa: ReaderTaskEither): ReaderTaskEither => fa.map(f) + +export const of = (a: A): ReaderTaskEither => new ReaderTaskEither(readerTTaskEither.of(a)) + +export const ap = ( + fab: ReaderTaskEither B>, + fa: ReaderTaskEither +): ReaderTaskEither => fa.ap(fab) + +export const chain = ( + f: (a: A) => ReaderTaskEither, + fa: ReaderTaskEither +): ReaderTaskEither => fa.chain(f) + +export const ask = (e: E): ReaderTaskEither => new ReaderTaskEither(readerT.ask(taskEither)()) + +export const asks = (f: (e: E) => A): ReaderTaskEither => + new ReaderTaskEither(readerT.asks(taskEither)(f)) + +export const local = (f: (e: E) => E) => (fa: ReaderTaskEither): ReaderTaskEither => + new ReaderTaskEither(e => fa.run(f(e))) + +export const right = (fa: Task): ReaderTaskEither => + new ReaderTaskEither(() => taskEither.right(fa)) + +export const left = (fa: Task): ReaderTaskEither => new ReaderTaskEither(() => taskEither.left(fa)) + +export const fromEither = (fa: Either): ReaderTaskEither => + new ReaderTaskEither(() => taskEither.fromEither(fa)) + +export const tryCatch = (f: (e: E) => Promise, onrejected: (reason: {}) => L): ReaderTaskEither => + new ReaderTaskEither(e => taskEither.tryCatch(() => f(e), onrejected)) + +export const readerTaskEither: Monad = { + URI, + map, + of, + ap, + chain +} diff --git a/package-lock.json b/package-lock.json index eb25fc469..18f75a6a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "fp-ts", - "version": "0.5.3", + "version": "0.6.0-dev.20171016", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1029,9 +1029,9 @@ } }, "typescript": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.5.3.tgz", - "integrity": "sha512-ptLSQs2S4QuS6/OD1eAKG+S5G8QQtrU5RT32JULdZQtM1L3WTi34Wsu48Yndzi8xsObRAB9RPt/KhA9wlpEF6w==", + "version": "2.6.0-rc", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.6.0-rc.tgz", + "integrity": "sha512-5dDv8NNGYmipBdXnt9mqWqIbzQ/mY5XWjrLeNEROmkHGJ6TnacHUihXi2SvKMHQsCafbJZqaSO+agMRl8F36GA==", "dev": true }, "unzip-response": { diff --git a/package.json b/package.json index d10250cd3..db5ecc89d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fp-ts", - "version": "0.5.4", + "version": "0.6.0-dev.20171016", "description": "Functional programming in TypeScript", "files": ["lib"], "main": "lib/index.js", @@ -36,7 +36,7 @@ "ts-node": "3.1.0", "tslint": "4.4.2", "tslint-config-standard": "4.0.0", - "typescript": "^2.5.2" + "typescript": "2.6.0-rc" }, "tags": ["typescript", "static-land", "fantasy-land", "algebraic-data-types", "functional-programming"], "keywords": ["typescript", "static-land", "fantasy-land", "algebraic-data-types", "functional-programming"] diff --git a/src/Alt.ts b/src/Alt.ts index 6a73a8af7..be631e925 100644 --- a/src/Alt.ts +++ b/src/Alt.ts @@ -2,9 +2,9 @@ import { HKT } from './HKT' import { Functor, FantasyFunctor } from './Functor' export interface Alt extends Functor { - alt: (fx: HKT) => (fy: HKT) => HKT + alt(fx: HKT, fy: HKT): HKT } export interface FantasyAlt extends FantasyFunctor { - alt: (fy: HKT) => HKT + alt(fy: HKT): HKT } diff --git a/src/Applicative.ts b/src/Applicative.ts index 89b4378b5..27ec934fe 100644 --- a/src/Applicative.ts +++ b/src/Applicative.ts @@ -1,4 +1,4 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Apply, FantasyApply } from './Apply' import { getFunctorComposition, @@ -17,39 +17,42 @@ export interface FantasyApplicative extends FantasyApply {} export interface ApplicativeComposition extends FunctorComposition { of: (a: A) => HKT> - ap: (fgab: HKT B>>, fga: HKT>) => HKT> + ap(fgab: HKT B>>, fga: HKT>): HKT> } export interface ApplicativeComposition11 extends FunctorComposition11 { of: (a: A) => HKTAs> - ap: (fgab: HKTAs B>>, fga: HKTAs>) => HKTAs> + ap(fgab: HKTAs B>>, fga: HKTAs>): HKTAs> } export interface ApplicativeComposition12 extends FunctorComposition12 { of: (a: A) => HKTAs> - ap: (fgab: HKTAs B>>, fga: HKTAs>) => HKTAs> + ap(fgab: HKTAs B>>, fga: HKTAs>): HKTAs> } export interface ApplicativeComposition21 extends FunctorComposition21 { of: (a: A) => HKT2As> - ap: (fgab: HKT2As B>>, fga: HKT2As>) => HKT2As> + ap(fgab: HKT2As B>>, fga: HKT2As>): HKT2As> } export interface ApplicativeComposition22 extends FunctorComposition22 { of: (a: A) => HKT2As> - ap: ( + ap( fgab: HKT2As B>>, fga: HKT2As> - ) => HKT2As> + ): HKT2As> } export class Ops { /** Perform a applicative action when a condition is true */ - when(F: Applicative): (condition: boolean) => (fu: HKT2As) => HKT2As - when(F: Applicative): (condition: boolean) => (fu: HKTAs) => HKTAs - when(F: Applicative): (condition: boolean) => (fu: HKT) => HKT - when(F: Applicative): (condition: boolean) => (fu: HKT) => HKT { - return condition => fu => (condition ? fu : F.of(undefined)) + when( + F: Applicative + ): (condition: boolean, fu: HKT3As) => HKT3As + when(F: Applicative): (condition: boolean, fu: HKT2As) => HKT2As + when(F: Applicative): (condition: boolean, fu: HKTAs) => HKTAs + when(F: Applicative): (condition: boolean, fu: HKT) => HKT + when(F: Applicative): (condition: boolean, fu: HKT) => HKT { + return (condition, fu) => (condition ? fu : F.of(undefined)) } getApplicativeComposition( diff --git a/src/Apply.ts b/src/Apply.ts index e57269a6f..08cfc6696 100644 --- a/src/Apply.ts +++ b/src/Apply.ts @@ -1,9 +1,9 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Functor, FantasyFunctor } from './Functor' import { Curried2, Curried3, Curried4, identity, constant } from './function' export interface Apply extends Functor { - ap: (fab: HKT B>, fa: HKT) => HKT + ap(fab: HKT B>, fa: HKT): HKT } /* @@ -14,11 +14,14 @@ export interface Apply extends Functor { */ export interface FantasyApply extends FantasyFunctor { - ap: (fab: HKT B>) => HKT + ap(fab: HKT B>): HKT } export class Ops { /** Combine two effectful actions, keeping only the result of the first */ + applyFirst( + apply: Apply + ): (fa: HKT3As) => (fb: HKT3As) => HKT3As applyFirst( apply: Apply ): (fa: HKT2As) => (fb: HKT2As) => HKT2As @@ -29,6 +32,9 @@ export class Ops { } /** Combine two effectful actions, keeping only the result of the second */ + applySecond( + apply: Apply + ): (fa: HKT3As) => (fb: HKT3As) => HKT3As applySecond( apply: Apply ): (fa: HKT2As) => (fb: HKT2As) => HKT2As @@ -42,6 +48,9 @@ export class Ops { * Lift a function of two arguments to a function which accepts and returns * values wrapped with the type constructor `F` */ + liftA2( + apply: Apply + ): (f: Curried2) => (fa: HKT3As) => (fb: HKT3As) => HKT3As liftA2( apply: Apply ): (f: Curried2) => (fa: HKT2As) => (fb: HKT2As) => HKT2As @@ -57,6 +66,11 @@ export class Ops { * Lift a function of three arguments to a function which accepts and returns * values wrapped with the type constructor `F` */ + liftA3( + apply: Apply + ): ( + f: Curried3 + ) => (fa: HKT3As) => (fb: HKT3As) => (fc: HKT3As) => HKT3As liftA3( apply: Apply ): ( @@ -78,6 +92,13 @@ export class Ops { * Lift a function of four arguments to a function which accepts and returns * values wrapped with the type constructor `F` */ + liftA4( + apply: Apply + ): ( + f: Curried4 + ) => ( + fa: HKT3As + ) => (fb: HKT3As) => (fc: HKT3As) => (fd: HKT3As) => HKT3As liftA4( apply: Apply ): ( diff --git a/src/Array.ts b/src/Array.ts index 28b004003..c810db049 100644 --- a/src/Array.ts +++ b/src/Array.ts @@ -12,9 +12,6 @@ import { Option, fromNullable } from './Option' import * as option from './Option' import { Ord, toNativeComparator } from './Ord' import { Extend } from './Extend' -import { Filterable } from './Filterable' -import { Either } from './Either' -import { Witherable } from './Witherable' import { Predicate, identity, constant, Lazy, Endomorphism, Refinement, tuple } from './function' // Adapted from https://github.com/purescript/purescript-arrays @@ -57,7 +54,7 @@ export class Ops { F: Applicative ): (f: (a: A) => HKT2As, ta: Array) => HKT2As> traverse(F: Applicative): (f: (a: A) => HKTAs, ta: Array) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Array) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Array) => HKT> { const liftedSnoc: (fa: HKT>) => (fb: HKT) => HKT> = liftA2(F)(snoc) return (f, ta) => reduce((fab, a) => liftedSnoc(fab)(f(a)), F.of(empty()), ta) @@ -69,7 +66,7 @@ export const traverse: Ops['traverse'] = ops.traverse export const zero = empty -export const alt = (x: Array) => (y: Array): Array => x.concat(y) +export const alt = (x: Array, y: Array): Array => x.concat(y) export const unfoldr = (f: (b: B) => Option<[A, B]>, b: B): Array => { const ret: Array = [] @@ -89,20 +86,6 @@ export const unfoldr = (f: (b: B) => Option<[A, B]>, b: B): Array => { export const extend = (f: (fa: Array) => B, fa: Array): Array => fa.map((_, i, as) => f(as.slice(i))) -export const partitionMap = (f: (a: A) => Either, fa: Array): { left: Array; right: Array } => { - const left: Array = [] - const right: Array = [] - for (let i = 0; i < fa.length; i++) { - f(fa[i]).fold(l => left.push(l), r => right.push(r)) - } - return { left, right } -} - -export const wilt = (M: Applicative) => ( - f: (a: A) => HKT>, - ta: Array -): HKT; right: Array }> => M.map(es => partitionMap(e => e, es), traverse(M)(f, ta)) - /** Break an array into its first element and remaining elements */ export const fold = (nil: Lazy, cons: (head: A, tail: Array) => B, as: Array): B => as.length === 0 ? nil() : cons(as[0], as.slice(1)) @@ -278,7 +261,7 @@ export const reverse = (as: Array): Array => copy(as).reverse() * which contain a value, creating a new array */ export const mapOption = (f: (a: A) => Option) => (as: Array): Array => - chain(a => option.fold(empty, of, f(a)), as) + chain(a => f(a).fold(empty, of), as) /** * Filter an array of optional values, keeping only the elements which contain @@ -316,9 +299,7 @@ export const array: Monoid> & Traversable & Alternative & Plus & - Extend & - Filterable & - Witherable = { + Extend = { URI, empty, concat, @@ -331,7 +312,5 @@ export const array: Monoid> & traverse, zero, alt, - extend, - partitionMap, - wilt + extend } diff --git a/src/Bifunctor.ts b/src/Bifunctor.ts index 235ada681..ae970a0aa 100644 --- a/src/Bifunctor.ts +++ b/src/Bifunctor.ts @@ -2,9 +2,9 @@ import { HKT2 } from './HKT' export interface Bifunctor { readonly URI: F - bimap: (f: (u: L) => M, g: (a: A) => B) => (fla: HKT2) => HKT2 + bimap(f: (u: L) => M, g: (a: A) => B, fla: HKT2): HKT2 } export interface FantasyBifunctor { - bimap: (f: (l: L) => M, g: (a: A) => B) => HKT2 + bimap(f: (l: L) => M, g: (a: A) => B): HKT2 } diff --git a/src/Chain.ts b/src/Chain.ts index 0a1ff79e9..650c1f451 100644 --- a/src/Chain.ts +++ b/src/Chain.ts @@ -1,16 +1,16 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Apply, FantasyApply } from './Apply' -import { Kleisli } from './function' export interface Chain extends Apply { - chain: (f: Kleisli, fa: HKT) => HKT + chain(f: (a: A) => HKT, fa: HKT): HKT } export interface FantasyChain extends FantasyApply { - chain: (f: Kleisli) => HKT + chain(f: (a: A) => HKT): HKT } export class Ops { + flatten(chain: Chain): (mma: HKT3As>) => HKT3As flatten(chain: Chain): (mma: HKT2As>) => HKT2As flatten(chain: Chain): (mma: HKTAs>) => HKTAs flatten(chain: Chain): (mma: HKT>) => HKT diff --git a/src/ChainRec.ts b/src/ChainRec.ts index 68d07ebe0..49b866f15 100644 --- a/src/ChainRec.ts +++ b/src/ChainRec.ts @@ -4,11 +4,11 @@ import { Either } from './Either' import { isLeft } from './Either' export interface ChainRec extends Chain { - chainRec: (f: (a: A) => HKT>, a: A) => HKT + chainRec(f: (a: A) => HKT>, a: A): HKT } export interface FantasyChainRec extends FantasyChain { - chainRec: (f: (a: A) => HKT>) => HKT + chainRec(f: (a: A) => HKT>): HKT } export const tailRec = (f: (a: A) => Either, a: A): B => { diff --git a/src/Comonad.ts b/src/Comonad.ts index b64daea07..7b6d720b0 100644 --- a/src/Comonad.ts +++ b/src/Comonad.ts @@ -2,7 +2,7 @@ import { HKT } from './HKT' import { Extend, FantasyExtend } from './Extend' export interface Comonad extends Extend { - extract: (ca: HKT) => A + extract(ca: HKT): A } export interface FantasyComonad extends FantasyExtend { diff --git a/src/Const.ts b/src/Const.ts index 281c359ae..cf4cdc507 100644 --- a/src/Const.ts +++ b/src/Const.ts @@ -31,9 +31,6 @@ export class Const implements FantasyFunctor, FantasyContravariant fold(f: (l: L) => B): B { return f(this.value) } - equals(S: Setoid, fy: Const): boolean { - return this.fold(x => fy.fold(y => S.equals(x)(y))) - } inspect() { return this.toString() } @@ -42,36 +39,29 @@ export class Const implements FantasyFunctor, FantasyContravariant } } -export const equals = (S: Setoid) => (fx: Const) => (fy: Const): boolean => { - return fx.equals(S, fy) -} - export const getSetoid = (S: Setoid): Setoid> => ({ - equals: x => y => equals(S)(x)(y) + equals: x => y => x.fold(ax => y.fold(ay => S.equals(ax)(ay))) }) export const map = (f: (a: A) => B, fa: Const): Const => fa.map(f) -export const contramap = (fa: Const): ((f: (b: B) => A) => Const) => (f: (b: B) => A) => - fa.contramap(f) +export const contramap = (f: (b: B) => A, fa: Const): Const => fa.contramap(f) + +export const ap = (S: Semigroup) => (fab: Const B>, fa: Const): Const => + new Const(S.concat(fab.fold(identity))(fa.fold(identity))) export const getApply = (S: Semigroup): Apply => ({ URI, map, - ap(fab: Const B>, fa: Const): Const { - return new Const(S.concat(fab.fold(identity))(fa.fold(identity))) - } + ap: ap(S) }) -export const getApplicative = (M: Monoid): Applicative => { - const empty = new Const(M.empty()) - return { - ...getApply(M), - of(b: A): Const { - return empty - } - } -} +export const of = (M: Monoid) => (b: A): Const => new Const(M.empty()) + +export const getApplicative = (M: Monoid): Applicative => ({ + ...getApply(M), + of: of(M) +}) export const const_: Functor & Contravariant = { URI, diff --git a/src/Contravariant.ts b/src/Contravariant.ts index 4cb944f9c..eba5a0559 100644 --- a/src/Contravariant.ts +++ b/src/Contravariant.ts @@ -1,22 +1,25 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' export interface Contravariant { readonly URI: F - contramap: (fa: HKT) => (f: (b: B) => A) => HKT + contramap(f: (b: B) => A, fa: HKT): HKT } export interface FantasyContravariant { - contramap: (f: (b: B) => A) => HKT + contramap(f: (b: B) => A): HKT } export class Ops { + lift( + contravariant: Contravariant + ): (f: (b: B) => A) => (fa: HKT3As) => HKT3As lift( contravariant: Contravariant ): (f: (b: B) => A) => (fa: HKT2As) => HKT2As lift(contravariant: Contravariant): (f: (b: B) => A) => (fa: HKTAs) => HKTAs lift(contravariant: Contravariant): (f: (b: B) => A) => (fa: HKT) => HKT lift(contravariant: Contravariant): (f: (b: B) => A) => (fa: HKT) => HKT { - return f => fa => contravariant.contramap(fa)(f) + return f => fa => contravariant.contramap(f, fa) } } diff --git a/src/Either.ts b/src/Either.ts index 7db9b42f8..6e2a7b6b1 100644 --- a/src/Either.ts +++ b/src/Either.ts @@ -9,9 +9,6 @@ import { Bifunctor, FantasyBifunctor } from './Bifunctor' import { Alt, FantasyAlt } from './Alt' import { ChainRec, tailRec } from './ChainRec' import { Option, none, some } from './Option' -import { Monoid } from './Monoid' -import { Filterable } from './Filterable' -import { Witherable } from './Witherable' import { constFalse, Predicate, Lazy, toString } from './function' declare module './HKT' { @@ -71,16 +68,13 @@ export class Left fold(left: (l: L) => B, right: (a: A) => B): B { return left(this.value) } + getOrElseValue(a: A): A { + return a + } /** Returns the value from this `Right` or the given argument if this is a `Left` */ getOrElse(f: (l: L) => A): A { return f(this.value) } - getOrElseValue(value: A): A { - return value - } - equals(SL: Setoid, SA: Setoid): (fy: Either) => boolean { - return fy => fy.fold(SL.equals(this.value), constFalse) - } mapLeft(f: (l: L) => M): Either { return left(f(this.value)) } @@ -142,16 +136,13 @@ export class Right fold(left: (l: L) => B, right: (a: A) => B): B { return right(this.value) } - /** Returns the value from this `Right` or the given argument if this is a `Left` */ - getOrElse(f: (l: L) => A): A { + getOrElseValue(a: A): A { return this.value } - getOrElseValue(value: A): A { + /** Returns the value from this `Right` or the given argument if this is a `Left` */ + getOrElse(f: (l: L) => A): A { return this.value } - equals(SL: Setoid, SA: Setoid): (fy: Either) => boolean { - return fy => fy.fold(constFalse, y => SA.equals(this.value)(y)) - } mapLeft(f: (l: L) => M): Either { return this as any } @@ -166,20 +157,19 @@ export class Right } } -export const equals = (SL: Setoid, SA: Setoid) => (fx: Either) => (fy: Either): boolean => - fx.equals(SL, SA)(fy) +export const fold = (left: (l: L) => B, right: (a: A) => B) => (fa: Either): B => fa.fold(left, right) export const getSetoid = (SL: Setoid, SA: Setoid): Setoid> => ({ - equals: equals(SL, SA) + equals: x => y => + x.fold(lx => y.fold(ly => SL.equals(lx)(ly), constFalse), ax => y.fold(constFalse, ay => SA.equals(ax)(ay))) }) -export const fold = (left: (l: L) => B, right: (a: A) => B, fa: Either): B => fa.fold(left, right) +/** Returns the value from this `Right` or the given argument if this is a `Left` */ +export const getOrElseValue = (a: A) => (fa: Either): A => fa.getOrElseValue(a) /** Returns the value from this `Right` or the given argument if this is a `Left` */ export const getOrElse = (f: (l: L) => A) => (fa: Either): A => fa.getOrElse(f) -export const getOrElseValue = (value: A) => (fa: Either): A => fa.getOrElseValue(value) - export const map = (f: (a: A) => B, fa: Either): Either => fa.map(f) export const of = (a: A): Either => new Right(a) @@ -188,10 +178,9 @@ export const ap = (fab: Either B>, fa: Either): Eith export const chain = (f: (a: A) => Either, fa: Either): Either => fa.chain(f) -export const bimap = (f: (u: L) => V, g: (a: A) => B) => (fau: Either): Either => - fau.bimap(f, g) +export const bimap = (f: (u: L) => V, g: (a: A) => B, fla: Either): Either => fla.bimap(f, g) -export const alt = (fx: Either) => (fy: Either): Either => fx.alt(fy) +export const alt = (fx: Either, fy: Either): Either => fx.alt(fy) export const extend = (f: (ea: Either) => B, ea: Either): Either => ea.extend(f) @@ -204,7 +193,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKT, ta: Either) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Either) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Either) => HKT> { return (f, ta) => ta.traverse(F)(f) } @@ -253,39 +242,6 @@ export const tryCatch = (f: Lazy): Either => { } } -export const getFilterable = (M: Monoid): Filterable => { - const empty = left(M.empty()) - function partitionMap(f: (a: A) => Either, fa: Either) { - return fa.fold( - l => ({ left: fa as any, right: fa as any }), - a => f(a).fold(l => ({ left: right(l), right: empty }), a => ({ left: empty, right: right(a) })) - ) - } - return { URI, map, partitionMap } -} - -export const getWitherable = (monoid: Monoid): Witherable => { - const empty = left(monoid.empty()) - function wilt( - applicative: Applicative - ): ( - f: (a: A) => HKT>, - ta: Either - ) => HKT; right: Either }> { - return (f, ta) => - ta.fold( - () => applicative.of({ left: ta as any, right: ta as any }), - a => - applicative.map( - e => e.fold(l => ({ left: right(l), right: empty }), r => ({ left: empty, right: right(r) })), - f(a) - ) - ) - } - const filterable = getFilterable(monoid) - return { ...filterable, wilt, traverse, reduce } -} - export const either: Monad & Foldable & Traversable & diff --git a/src/Exception.ts b/src/Exception.ts index 2419cb9f9..8df052c66 100644 --- a/src/Exception.ts +++ b/src/Exception.ts @@ -33,7 +33,8 @@ export const catchException = (handler: (e: Error) => IO) => (action: IO(action: IO): IO> => diff --git a/src/Extend.ts b/src/Extend.ts index 4c48f5048..9d166fc76 100644 --- a/src/Extend.ts +++ b/src/Extend.ts @@ -1,16 +1,18 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' -import { Cokleisli } from './function' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Functor, FantasyFunctor } from './Functor' export interface Extend extends Functor { - extend: (f: Cokleisli, ea: HKT) => HKT + extend(f: (fa: HKT) => B, ea: HKT): HKT } export interface FantasyExtend extends FantasyFunctor { - extend: (f: Cokleisli) => HKT + extend(f: (fa: HKT) => B): HKT } export class Ops { + duplicate( + extend: Extend + ): (ma: HKT3As) => HKT3As> duplicate(extend: Extend): (ma: HKT2As) => HKT2As> duplicate(extend: Extend): (ma: HKTAs) => HKTAs> duplicate(extend: Extend): (ma: HKT) => HKT> diff --git a/src/Filterable.ts b/src/Filterable.ts deleted file mode 100644 index edf23053f..000000000 --- a/src/Filterable.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' -import { Functor, FantasyFunctor } from './Functor' -import { Either, fromPredicate, left, right } from './Either' -import { Option, fromPredicate as optionFromPredicate } from './Option' -import { Predicate, identity } from './function' - -export interface Filterable extends Functor { - /** partition a data structure based on an either predicate */ - partitionMap: (f: (a: A) => Either, fa: HKT) => { left: HKT; right: HKT } -} - -export interface FantasyFilterable extends FantasyFunctor { - /** partition a data structure based on an either predicate */ - partitionMap: (f: (a: A) => Either) => { left: HKT; right: HKT } -} - -export class Ops { - /** partition a data structure based on boolean predicate */ - partition( - F: Filterable - ): (predicate: Predicate) => (fa: HKT2As) => { no: HKT2As; yes: HKT2As } - partition( - F: Filterable - ): (predicate: Predicate) => (fa: HKTAs) => { no: HKTAs; yes: HKTAs } - partition(F: Filterable): (predicate: Predicate) => (fa: HKT) => { no: HKT; yes: HKT } - partition(F: Filterable): (predicate: Predicate) => (fa: HKT) => { no: HKT; yes: HKT } { - return predicate => fa => { - const { left, right } = F.partitionMap(fromPredicate(predicate, identity), fa) - return { no: left, yes: right } - } - } - - /** map over a data structure and filter based on a maybe */ - filterMap( - F: Filterable - ): (f: (a: A) => Option) => (fa: HKT2As) => HKT2As - filterMap(F: Filterable): (f: (a: A) => Option) => (fa: HKTAs) => HKTAs - filterMap(F: Filterable): (f: (a: A) => Option) => (fa: HKT) => HKT - filterMap(F: Filterable): (f: (a: A) => Option) => (fa: HKT) => HKT { - return (f: (a: A) => Option) => (fa: HKT) => - F.partitionMap((a: A) => f(a).fold(() => left(null), b => right(b)), fa).right - } - - /** filter a data structure based on a boolean */ - filter(F: Filterable): (predicate: Predicate) => (fa: HKT2As) => HKT2As - filter(F: Filterable): (predicate: Predicate) => (fa: HKTAs) => HKTAs - filter(F: Filterable): (predicate: Predicate) => (fa: HKT) => HKT - filter(F: Filterable): (predicate: Predicate) => (fa: HKT) => HKT { - return (predicate: Predicate) => (fa: HKT) => this.filterMap(F)(optionFromPredicate(predicate))(fa) - } - - partitioned( - F: Filterable - ): (fa: HKT2As>) => { left: HKT2As; right: HKT2As } - partitioned( - F: Filterable - ): (fa: HKTAs>) => { left: HKTAs; right: HKTAs } - partitioned(F: Filterable): (fa: HKT>) => { left: HKT; right: HKT } - partitioned(F: Filterable): (fa: HKT>) => { left: HKT; right: HKT } { - return (fa: HKT>) => F.partitionMap(a => a, fa) - } - - /** Filter out all the `None` values */ - filtered(F: Filterable): (fa: HKT2As>) => HKT2As - filtered(F: Filterable): (fa: HKTAs>) => HKTAs - filtered(F: Filterable): (fa: HKT>) => HKT - filtered(F: Filterable): (fa: HKT>) => HKT { - return (fa: HKT>) => this.filterMap(F)((oa: Option) => oa)(fa) - } -} - -const ops = new Ops() -export const partition: Ops['partition'] = ops.partition -export const filterMap: Ops['filterMap'] = ops.filterMap -export const filter: Ops['filter'] = ops.filter -export const partitioned: Ops['partitioned'] = ops.partitioned -export const filtered: Ops['filtered'] = ops.filtered diff --git a/src/Foldable.ts b/src/Foldable.ts index c49ca3bb6..8a3383510 100644 --- a/src/Foldable.ts +++ b/src/Foldable.ts @@ -1,4 +1,4 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Monoid, getEndomorphismMonoid, monoidArray } from './Monoid' import { Applicative } from './Applicative' import { applyFirst } from './Apply' @@ -6,15 +6,15 @@ import { identity } from './function' export interface Foldable { readonly URI: F - reduce: (f: (b: B, a: A) => B, b: B, fa: HKT) => B + reduce(f: (b: B, a: A) => B, b: B, fa: HKT): B } export interface FantasyFoldable { - reduce: (f: (b: B, a: A) => B, b: B) => B + reduce(f: (b: B, a: A) => B, b: B): B } export interface FoldableComposition { - reduce: (f: (b: B, a: A) => B, b: B, fga: HKT>) => B + reduce(f: (b: B, a: A) => B, b: B, fga: HKT>): B } export const getFoldableComposition = (F: Foldable, G: Foldable): FoldableComposition => { @@ -53,6 +53,10 @@ export class Ops { * Traverse a data structure, performing some effects encoded by an * `Applicative` functor at each value, ignoring the final result. */ + traverse_( + M: Applicative, + F: Foldable + ): (f: (a: A) => HKT3As, fa: HKT) => HKT3As traverse_( M: Applicative, F: Foldable @@ -70,6 +74,10 @@ export class Ops { * Perform all of the effects in some data structure in the order * given by the `Foldable` instance, ignoring the final result. */ + sequence_( + M: Applicative, + F: Foldable + ): (fa: HKT>) => HKT3As sequence_( M: Applicative, F: Foldable diff --git a/src/Free.ts b/src/Free.ts index 0889ed878..e7ee71b1a 100644 --- a/src/Free.ts +++ b/src/Free.ts @@ -1,7 +1,7 @@ // adapted from http://okmij.org/ftp/Computation/free-monad.html // and https://github.com/purescript/purescript-free -import { HKT, HKTS, HKTAs, HKT2S, HKT2As } from './HKT' +import { HKT, HKTS, HKTAs, HKT2S, HKT2As, HKT3S, HKT3As } from './HKT' import { FantasyMonad, Monad } from './Monad' import { NaturalTransformation } from './NaturalTransformation' import { toString } from './function' @@ -94,6 +94,9 @@ export const hoistFree = (f: NaturalTransformation): ((fa: Free liftF(f(fa))) export class Ops { + foldFree( + M: Monad + ): (f: NaturalTransformation) => (fa: Free) => HKT3As foldFree( M: Monad ): (f: NaturalTransformation) => (fa: Free) => HKT2As diff --git a/src/Functor.ts b/src/Functor.ts index b483425fb..a5a583397 100644 --- a/src/Functor.ts +++ b/src/Functor.ts @@ -1,33 +1,33 @@ -import { HKT, HKT2, HKTAs, HKTS, HKT2As, HKT2S } from './HKT' +import { HKT, HKT2, HKTAs, HKTS, HKT2As, HKT2S, HKT3S, HKT3As, HKT3 } from './HKT' import { constant } from './function' export interface Functor { readonly URI: F - map: (f: (a: A) => B, fa: HKT) => HKT + map(f: (a: A) => B, fa: HKT): HKT } export interface FantasyFunctor { - map: (f: (a: A) => B) => HKT + map(f: (a: A) => B): HKT } export interface FunctorComposition { - map: (f: (a: A) => B, fa: HKT>) => HKT> + map(f: (a: A) => B, fa: HKT>): HKT> } export interface FunctorComposition11 { - map: (f: (a: A) => B, fa: HKTAs>) => HKTAs> + map(f: (a: A) => B, fa: HKTAs>): HKTAs> } export interface FunctorComposition12 { - map: (f: (a: A) => B, fa: HKTAs>) => HKTAs> + map(f: (a: A) => B, fa: HKTAs>): HKTAs> } export interface FunctorComposition21 { - map: (f: (a: A) => B, fa: HKT2As>) => HKT2As> + map(f: (a: A) => B, fa: HKT2As>): HKT2As> } export interface FunctorComposition22 { - map: (f: (a: A) => B, fa: HKT2As>) => HKT2As> + map(f: (a: A) => B, fa: HKT2As>): HKT2As> } export class Ops { @@ -35,6 +35,7 @@ export class Ops { * Lift a function of one argument to a function which accepts and returns * values wrapped with the type constructor `F` */ + lift(F: Functor): (f: (a: A) => B) => (fa: HKT3As) => HKT3As lift(F: Functor): (f: (a: A) => B) => (fa: HKT2As) => HKT2As lift(F: Functor): (f: (a: A) => B) => (fa: HKTAs) => HKTAs lift(F: Functor): (f: (a: A) => B) => (fa: HKT) => HKT @@ -43,6 +44,7 @@ export class Ops { } /** Ignore the return value of a computation, using the specified return value instead (`<$`) */ + voidRight(F: Functor): (a: A) => (fb: HKT3) => HKT3As voidRight(F: Functor): (a: A) => (fb: HKT2) => HKT2As voidRight(F: Functor): (a: A) => (fb: HKT) => HKTAs voidRight(F: Functor): (a: A) => (fb: HKT) => HKT @@ -51,6 +53,7 @@ export class Ops { } /** A version of `voidRight` with its arguments flipped (`$>`) */ + voidLeft(F: Functor): (fa: HKT3) => (b: B) => HKT3As voidLeft(F: Functor): (fa: HKT2) => (b: B) => HKT2As voidLeft(F: Functor): (fa: HKT) => (b: B) => HKTAs voidLeft(F: Functor): (fa: HKT) => (b: B) => HKT @@ -62,6 +65,9 @@ export class Ops { * Apply a value in a computational context to a value in no context. * Generalizes `flip` */ + flap( + functor: Functor + ): (ff: HKT3As B>) => (a: A) => HKT3As flap(functor: Functor): (ff: HKT2As B>) => (a: A) => HKT2As flap(functor: Functor): (ff: HKTAs B>) => (a: A) => HKTAs flap(functor: Functor): (ff: HKT B>) => (a: A) => HKT diff --git a/src/IO.ts b/src/IO.ts index 84605ab16..e45271df8 100644 --- a/src/IO.ts +++ b/src/IO.ts @@ -45,11 +45,8 @@ export const ap = (fab: IO<(a: A) => B>, fa: IO): IO => fa.ap(fab) export const chain = (f: (a: A) => IO, fa: IO): IO => fa.chain(f) -export const concat = (S: Semigroup) => (fx: IO) => (fy: IO): IO => - new IO(() => S.concat(fx.run())(fy.run())) - export const getSemigroup = (S: Semigroup): Semigroup> => ({ - concat: concat(S) + concat: x => y => new IO(() => S.concat(x.run())(y.run())) }) export const getMonoid = (M: Monoid): Monoid> => { diff --git a/src/Identity.ts b/src/Identity.ts index 6e4b1c0c9..9077df2bf 100644 --- a/src/Identity.ts +++ b/src/Identity.ts @@ -74,11 +74,8 @@ export class Identity } } -export const equals = (setoid: Setoid) => (fx: Identity) => (fy: Identity): boolean => - setoid.equals(fx.value)(fy.value) - export const getSetoid = (setoid: Setoid): Setoid> => ({ - equals: equals(setoid) + equals: x => y => setoid.equals(x.value)(y.value) }) export const map = (f: (a: A) => B, fa: Identity): Identity => fa.map(f) @@ -91,7 +88,7 @@ export const chain = (f: (a: A) => Identity, fa: Identity): Identity export const reduce = (f: (b: B, a: A) => B, b: B, fa: Identity): B => fa.reduce(f, b) -export const alt = (fx: Identity) => (fy: Identity): Identity => { +export const alt = (fx: Identity, fy: Identity): Identity => { return fx.alt(fy) } @@ -107,7 +104,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKTAs, ta: Identity) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Identity) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Identity) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/Invariant.ts b/src/Invariant.ts index 6d3bd6008..2d68e8ba3 100644 --- a/src/Invariant.ts +++ b/src/Invariant.ts @@ -2,5 +2,5 @@ import { HKT } from './HKT' export interface Invariant { readonly URI: F - imap: (f: (a: A) => B, g: (b: B) => A, fa: HKT) => HKT + imap(f: (a: A) => B, g: (b: B) => A, fa: HKT): HKT } diff --git a/src/IxMonad.ts b/src/IxMonad.ts index 9b41b9c26..067063607 100644 --- a/src/IxMonad.ts +++ b/src/IxMonad.ts @@ -5,12 +5,12 @@ import { constant } from './function' export interface IxMonad { readonly URI: F - iof: (a: A) => HKT3 - ichain: (f: (a: A) => HKT3, fa: HKT3) => HKT3 + iof(a: A): HKT3 + ichain(f: (a: A) => HKT3, fa: HKT3): HKT3 } export interface FantasyIxMonad { - ichain: (f: (a: A) => HKT3) => HKT3 + ichain(f: (a: A) => HKT3): HKT3 } export class Ops { diff --git a/src/Monoidal.ts b/src/Monoidal.ts index ebe006c3b..f481f0566 100644 --- a/src/Monoidal.ts +++ b/src/Monoidal.ts @@ -10,21 +10,20 @@ import { liftA2 } from './Apply' * - https://bartoszmilewski.com/2017/02/06/applicative-functors/ */ export interface Monoidal extends Functor { - readonly URI: F - unit: () => HKT - mult: (fa: HKT) => (fb: HKT) => HKT + unit(): HKT + mult(fa: HKT, fb: HKT): HKT } export const fromApplicative = (applicative: Applicative): Monoidal => ({ URI: applicative.URI, map: applicative.map, unit: () => applicative.of(undefined), - mult: liftA2(applicative)(tupleCurried) + mult: (fa: HKT, fb: HKT) => liftA2(applicative)(tupleCurried)(fa)(fb) }) export const toApplicative = (monoidal: Monoidal): Applicative => ({ URI: monoidal.URI, map: monoidal.map, of: a => monoidal.map(constant(a), monoidal.unit()), - ap: (fab, fa) => monoidal.map(([f, a]) => f(a), monoidal.mult(fab)(fa)) + ap: (fab, fa) => monoidal.map(([f, a]) => f(a), monoidal.mult(fab, fa)) }) diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts index aaa608cf6..6eb7f5b06 100644 --- a/src/NonEmptyArray.ts +++ b/src/NonEmptyArray.ts @@ -97,7 +97,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKTAs, ta: NonEmptyArray) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: NonEmptyArray) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: NonEmptyArray) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/Option.ts b/src/Option.ts index 9af35fbc8..1de166100 100644 --- a/src/Option.ts +++ b/src/Option.ts @@ -9,10 +9,7 @@ import { Extend, FantasyExtend } from './Extend' import { Setoid } from './Setoid' import { Traversable, FantasyTraversable } from './Traversable' import { Alternative, FantasyAlternative } from './Alternative' -import { Filterable, FantasyFilterable } from './Filterable' -import { Either } from './Either' -import { Witherable, FantasyWitherable } from './Witherable' -import { constant, constFalse, constTrue, Lazy, Predicate, toString } from './function' +import { constant, Lazy, Predicate, toString } from './function' declare module './HKT' { interface URI2HKT { @@ -30,8 +27,6 @@ export class None implements FantasyMonad, FantasyFoldable, FantasyTraversable, - FantasyFilterable, - FantasyWitherable, FantasyAlternative, FantasyExtend { static value: Option = new None() @@ -64,14 +59,6 @@ export class None traverse(F: Applicative): (f: (a: A) => HKT) => HKT> { return f => F.of(none) } - partitionMap(f: (a: A) => Either): { left: Option; right: Option } { - return { left: none, right: none } - } - wilt( - M: Applicative - ): (f: (a: A) => HKT>) => HKT; right: Option }> { - return (f: (a: A) => HKT>) => M.of({ left: none, right: none }) - } alt(fa: Option): Option { return fa } @@ -81,18 +68,12 @@ export class None fold(n: Lazy, s: (a: A) => B): B { return n() } + getOrElseValue(a: A): A { + return a + } getOrElse(f: Lazy): A { return f() } - getOrElseValue(value: A): A { - return value - } - concat(S: Semigroup): (fy: Option) => Option { - return fy => fy - } - equals(S: Setoid): (fy: Option) => boolean { - return fy => fy.fold(constTrue, constFalse) - } toNullable(): A | null { return null } @@ -133,8 +114,6 @@ export class Some implements FantasyMonad, FantasyFoldable, FantasyTraversable, - FantasyFilterable, - FantasyWitherable, FantasyAlternative, FantasyExtend { readonly _tag: 'Some' = 'Some' @@ -166,25 +145,6 @@ export class Some traverse(F: Applicative): (f: (a: A) => HKT) => HKT> { return f => F.map(b => some(b), f(this.value)) } - partitionMap(f: (a: A) => Either): { left: Option; right: Option } { - return f(this.value).fold<{ left: Option; right: Option }>( - l => ({ left: some(l), right: none }), - a => ({ left: none, right: some(a) }) - ) - } - wilt( - M: Applicative - ): (f: (a: A) => HKT>) => HKT; right: Option }> { - return (f: (a: A) => HKT>) => - M.map( - e => - e.fold<{ left: Option; right: Option }>( - l => ({ left: some(l), right: none }), - r => ({ left: none, right: some(r) }) - ), - f(this.value) - ) - } alt(fa: Option): Option { return this } @@ -194,18 +154,12 @@ export class Some fold(n: Lazy, s: (a: A) => B): B { return s(this.value) } - getOrElse(f: Lazy): A { + getOrElseValue(a: A): A { return this.value } - getOrElseValue(value: A): A { + getOrElse(f: Lazy): A { return this.value } - concat(S: Semigroup): (fy: Option) => Option { - return fy => fy.fold(() => this, y => new Some(S.concat(this.value)(y))) - } - equals(S: Setoid): (fy: Option) => boolean { - return fy => fy.fold(constFalse, y => S.equals(this.value)(y)) - } toNullable(): A | null { return this.value } @@ -240,10 +194,10 @@ export class Some } } -export const equals = (S: Setoid) => (fx: Option) => (fy: Option): boolean => fx.equals(S)(fy) +export const fold = (n: Lazy, s: (a: A) => B) => (fa: Option): B => fa.fold(n, s) export const getSetoid = (S: Setoid): Setoid> => ({ - equals: equals(S) + equals: x => y => x.fold(() => y.isNone(), ax => y.fold(() => false, ay => S.equals(ax)(ay))) }) export const map = (f: (a: A) => B, fa: Option): Option => fa.map(f) @@ -262,12 +216,7 @@ export const reduce = (f: (b: B, a: A) => B, b: B, fa: Option): B => fa /** Returns this option if it is non empty and the predicate `p` return `true` when applied to this Option's value. Otherwise returns none */ export const filter = (p: Predicate) => (fa: Option): Option => fa.filter(p) -// overload here to support 'None' as first argument -export function alt(fx: Option): (fy: Option) => Option -export function alt(fx: Option): (fy: Option) => Option -export function alt(fx: Option): (fy: Option) => Option { - return fy => fx.alt(fy) -} +export const alt = (fx: Option, fy: Option): Option => fx.alt(fy) export const extend = (f: (ea: Option) => B, ea: Option): Option => ea.extend(f) @@ -275,45 +224,33 @@ export const zero = (): Option => none export const empty = zero -const first = { empty, concat: alt } -const last = getDualMonoid(first) - -/** Option monoid returning the left-most non-`None` value */ -export const getFirstMonoid = (): Monoid> => first - -/** Option monoid returning the right-most non-`None` value */ -export const getLastMonoid = (): Monoid> => last +/** Option monoid returning the left-most non-None value */ +export const getFirstMonoid = (): Monoid> => ({ + concat: x => y => alt(x, y), + empty +}) -export const concat = (S: Semigroup) => (fx: Option) => (fy: Option): Option => fx.concat(S)(fy) +/** Option monoid returning the right-most non-None value */ +export const getLastMonoid = (): Monoid> => getDualMonoid(getFirstMonoid()) export const getSemigroup = (S: Semigroup): Semigroup> => ({ - concat: concat(S) + concat: x => y => x.fold(() => y, ax => y.fold(() => x, ay => some(S.concat(ax)(ay)))) }) export const getMonoid = (S: Semigroup): Monoid> => ({ ...getSemigroup(S), empty }) -export const partitionMap = ( - f: (a: A) => Either, - fa: Option -): { left: Option; right: Option } => fa.partitionMap(f) - -export const wilt = (M: Applicative) => ( - f: (a: A) => HKT>, - ta: Option -): HKT; right: Option }> => ta.wilt(M)(f) - export const isSome = (fa: Option): fa is Some => fa._tag === 'Some' export const isNone = (fa: Option): fa is None => fa === none -export const fold = (n: Lazy, s: (a: A) => B, fa: Option): B => fa.fold(n, s) - /** * Takes a default value, and a `Option` value. If the `Option` value is * `None` the default value is returned, otherwise the value inside the * `Some` is returned */ -export const fromOption = (a: A) => (fa: Option): A => fa.getOrElseValue(a) +export const getOrElseValue = (a: A) => (fa: Option): A => fa.getOrElseValue(a) + +export const getOrElse = (f: Lazy) => (fa: Option): A => fa.getOrElse(f) export const fromNullable = (a: A | null | undefined): Option => (a == null ? none : new Some(a)) @@ -330,7 +267,7 @@ export class Ops { F: Applicative ): (f: (a: A) => HKT2As, ta: Option) => HKT2As> traverse(F: Applicative): (f: (a: A) => HKTAs, ta: Option) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Option) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Option) => HKT> { return (f, ta) => ta.traverse(F)(f) } @@ -339,14 +276,7 @@ export class Ops { const ops = new Ops() export const traverse: Ops['traverse'] = ops.traverse -export const option: Monad & - Foldable & - Plus & - Traversable & - Alternative & - Extend & - Filterable & - Witherable = { +export const option: Monad & Foldable & Plus & Traversable & Alternative & Extend = { URI, map, of, @@ -356,7 +286,5 @@ export const option: Monad & traverse, zero, alt, - extend, - partitionMap, - wilt + extend } diff --git a/src/Pair.ts b/src/Pair.ts index 402f002c1..2ca24ba23 100644 --- a/src/Pair.ts +++ b/src/Pair.ts @@ -88,23 +88,19 @@ export const getSetoid = (S: Setoid): Setoid> => ({ equals: x => y => S.equals(x.fst())(y.fst()) && S.equals(x.snd())(y.snd()) }) -export const getOrd = (O: Ord): Ord> => { - const S = getSetoid(O) - return { - ...S, - compare: x => y => orderingSemigroup.concat(O.compare(x.fst())(y.fst()))(O.compare(x.snd())(y.snd())) - } -} +export const getOrd = (O: Ord): Ord> => ({ + ...getSetoid(O), + compare: x => y => orderingSemigroup.concat(O.compare(x.fst())(y.fst()))(O.compare(x.snd())(y.snd())) +}) export const getSemigroup = (S: Semigroup): Semigroup> => ({ concat: x => y => new Pair([S.concat(x.fst())(y.fst()), S.concat(x.snd())(y.snd())]) }) export const getMonoid = (M: Monoid): Monoid> => { - const S = getSemigroup(M) const empty = new Pair([M.empty(), M.empty()]) return { - ...S, + ...getSemigroup(M), empty: () => empty } } @@ -123,7 +119,7 @@ export class Ops { F: Applicative ): (f: (a: A) => HKT2As, ta: Pair) => HKT2As> traverse(F: Applicative): (f: (a: A) => HKTAs, ta: Pair) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Pair) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Pair) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/Profunctor.ts b/src/Profunctor.ts index ae44dcaf6..e0962d6ec 100644 --- a/src/Profunctor.ts +++ b/src/Profunctor.ts @@ -1,18 +1,38 @@ -import { HKT2 } from './HKT' +import { HKT2, HKT2S, HKT2As, HKT3S, HKT3As } from './HKT' import { Functor, FantasyFunctor } from './Functor' export interface Profunctor extends Functor { - promap: (f: (a: A) => B, g: (c: C) => D) => (fbc: HKT2) => HKT2 + promap(f: (a: A) => B, g: (c: C) => D, fbc: HKT2): HKT2 } export interface FantasyProfunctor extends FantasyFunctor { promap: (f: (a: A) => B, g: (c: C) => D) => HKT2 } -export const lmap = (profunctor: Profunctor) => (f: (a: A) => B) => ( - fbc: HKT2 -): HKT2 => profunctor.promap(f, (c: C) => c)(fbc) +export class Ops { + lmap( + profunctor: Profunctor + ): (f: (a: A) => B) => (fbc: HKT3As) => HKT3As + lmap( + profunctor: Profunctor + ): (f: (a: A) => B) => (fbc: HKT2As) => HKT2As + lmap(profunctor: Profunctor): (f: (a: A) => B) => (fbc: HKT2) => HKT2 + lmap(profunctor: Profunctor): (f: (a: A) => B) => (fbc: HKT2) => HKT2 { + return f => fbc => profunctor.promap(f, c => c, fbc) + } -export const rmap = (profunctor: Profunctor) => (g: (c: C) => D) => ( - fbc: HKT2 -): HKT2 => profunctor.promap((b: B) => b, g)(fbc) + rmap( + profunctor: Profunctor + ): (g: (c: C) => D) => (fbc: HKT3As) => HKT3As + rmap( + profunctor: Profunctor + ): (g: (c: C) => D) => (fbc: HKT2As) => HKT2As + rmap(profunctor: Profunctor): (g: (c: C) => D) => (fbc: HKT2) => HKT2 + rmap(profunctor: Profunctor): (g: (c: C) => D) => (fbc: HKT2) => HKT2 { + return g => fbc => profunctor.promap(b => b, g, fbc) + } +} + +const ops = new Ops() +export const lmap: Ops['lmap'] = ops.lmap +export const rmap: Ops['rmap'] = ops.rmap diff --git a/src/Random.ts b/src/Random.ts index 586c7c69e..0a5d93053 100644 --- a/src/Random.ts +++ b/src/Random.ts @@ -2,23 +2,26 @@ import { IO } from './IO' // Adapted from https://github.com/purescript/purescript-random -/** Returns a random number between 0 (inclusive) and 1 (exclusive). This is +/** + * Returns a random number between 0 (inclusive) and 1 (exclusive). This is * a direct wrapper around JavaScript's `Math.random()`. */ -export const random = (): IO => new IO(() => Math.random()) +export const random: IO = new IO(() => Math.random()) -/** Takes a range specified by `low` (the first argument) and `high` (the +/** + * Takes a range specified by `low` (the first argument) and `high` (the * second), and returns a random integer uniformly distributed in the closed * interval `[low, high]`. It is unspecified what happens if `low > high`, * or if either of `low` or `high` is not an integer. */ export const randomInt = (low: number, high: number): IO => - random().map(n => Math.floor((high - low + 1) * n + low)) + random.map(n => Math.floor((high - low + 1) * n + low)) -/** Returns a random number between a minimum value (inclusive) and a maximum +/** + * Returns a random number between a minimum value (inclusive) and a maximum * value (exclusive). It is unspecified what happens if `maximum < minimum`. */ -export const randomRange = (min: number, max: number): IO => random().map(n => (max - min + 1) * n + min) +export const randomRange = (min: number, max: number): IO => random.map(n => (max - min + 1) * n + min) /** Returns a random boolean value with an equal chance of being `true` or `false` */ -export const randomBool = (): IO => random().map(n => n < 0.5) +export const randomBool: IO = random.map(n => n < 0.5) diff --git a/src/Reader.ts b/src/Reader.ts index 4af32c128..17ce6a784 100644 --- a/src/Reader.ts +++ b/src/Reader.ts @@ -1,5 +1,5 @@ import { Monad, FantasyMonad } from './Monad' -import { identity, Endomorphism } from './function' +import { identity } from './function' export const URI = 'Reader' @@ -36,8 +36,7 @@ export const ask = (): Reader => new Reader(identity) export const asks = (f: (e: E) => A): Reader => new Reader(f) /** changes the value of the local context during the execution of the action `fa` */ -export const local = (f: Endomorphism) => (fa: Reader): Reader => - new Reader((e: E) => fa.run(f(e))) +export const local = (f: (e: E) => E) => (fa: Reader): Reader => new Reader((e: E) => fa.run(f(e))) export const reader: Monad = { URI, diff --git a/src/Semigroupoid.ts b/src/Semigroupoid.ts index d3f9b5ca9..06e117921 100644 --- a/src/Semigroupoid.ts +++ b/src/Semigroupoid.ts @@ -2,9 +2,9 @@ import { HKT2 } from './HKT' export interface Semigroupoid { readonly URI: F - compose: (bc: HKT2) => (ab: HKT2) => HKT2 + compose(bc: HKT2, ab: HKT2): HKT2 } export interface FantasySemigroupoid { - compose: (bc: HKT2) => HKT2 + compose(bc: HKT2): HKT2 } diff --git a/src/StrMap.ts b/src/StrMap.ts index d554c9b97..330d76a0c 100644 --- a/src/StrMap.ts +++ b/src/StrMap.ts @@ -93,7 +93,7 @@ export class Ops { F: Applicative ): (f: (a: A) => HKT2As, ta: StrMap) => HKT2As> traverse(F: Applicative): (f: (a: A) => HKTAs, ta: StrMap) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: StrMap) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: StrMap) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/TaskEither.ts b/src/TaskEither.ts index 712fe11b7..99cca443a 100644 --- a/src/TaskEither.ts +++ b/src/TaskEither.ts @@ -17,6 +17,10 @@ export const URI = 'TaskEither' export type URI = typeof URI +const eitherTfold = eitherT.fold(task) +const eitherTmapLeft = eitherT.mapLeft(task) +const eitherTtoOption = eitherT.toOption(task) + export class TaskEither implements FantasyMonad { readonly _A: A readonly _L: L @@ -35,13 +39,13 @@ export class TaskEither implements FantasyMonad { return new TaskEither(eitherTTask.chain(a => f(a).value, this.value)) } fold(left: (l: L) => R, right: (a: A) => R): task.Task { - return eitherT.fold(task)(left, right, this.value) + return eitherTfold(left, right, this.value) } mapLeft(f: (l: L) => M): TaskEither { - return new TaskEither(eitherT.mapLeft(task)(f)(this.value)) + return new TaskEither(eitherTmapLeft(f)(this.value)) } toOption(): task.Task> { - return eitherT.toOption(task)(this.value) + return eitherTtoOption(this.value) } } @@ -53,12 +57,14 @@ export const ap = (fab: TaskEither B>, fa: TaskEither(f: (a: A) => TaskEither, fa: TaskEither): TaskEither => fa.chain(f) -export const right = (fa: task.Task): TaskEither => new TaskEither(eitherT.right(task)(fa)) +const eitherTright = eitherT.right(task) +export const right = (fa: task.Task): TaskEither => new TaskEither(eitherTright(fa)) -export const left = (fa: task.Task): TaskEither => new TaskEither(eitherT.left(task)(fa)) +const eitherTleft = eitherT.left(task) +export const left = (fa: task.Task): TaskEither => new TaskEither(eitherTleft(fa)) -export const fromEither = (fa: either.Either): TaskEither => - new TaskEither(eitherT.fromEither(task)(fa)) +const eitherTfromEither = eitherT.fromEither(task) +export const fromEither = (fa: either.Either): TaskEither => new TaskEither(eitherTfromEither(fa)) export const tryCatch = (f: Lazy>, onrejected: (reason: {}) => L): TaskEither => new TaskEither(task.tryCatch(f)(onrejected)) diff --git a/src/These.ts b/src/These.ts index 9afc2e571..91ffb18da 100644 --- a/src/These.ts +++ b/src/These.ts @@ -7,7 +7,7 @@ import { Traversable, FantasyTraversable } from './Traversable' import { Option, none, some } from './Option' import { Setoid } from './Setoid' import { Semigroup } from './Semigroup' -import { constFalse, toString } from './function' +import { toString, constFalse } from './function' import { Monad } from './Monad' // Data type isomorphic to `α ∨ β ∨ (α ∧ β)` @@ -35,12 +35,6 @@ export class This map(f: (a: A) => B): These { return this as any } - ap(SL: Semigroup, fab: These B>): These { - return fab.fold(() => fab as any, () => this as any, (l, _) => this_(SL.concat(l)(this.value))) - } - chain(SL: Semigroup, f: (a: A) => These): These { - return this as any - } bimap(f: (l: L) => M, g: (a: A) => B): These { return this_(f(this.value)) } @@ -56,17 +50,6 @@ export class This fold(this_: (l: L) => B, that: (a: A) => B, both: (l: L, a: A) => B): B { return this_(this.value) } - equals(setoidL: Setoid, setoidA: Setoid): (fy: These) => boolean { - return fy => fy.fold(l => setoidL.equals(l)(this.value), constFalse, constFalse) - } - concat(SL: Semigroup, SA: Semigroup): (fy: These) => These { - return fy => - fy.fold( - l => this_(SL.concat(this.value)(l)), - a => both(this.value, a), - (l, a) => both(SL.concat(this.value)(l), a) - ) - } inspect() { return this.toString() } @@ -85,12 +68,6 @@ export class That map(f: (a: A) => B): These { return new That(f(this.value)) } - ap(SL: Semigroup, fab: These B>): These { - return fab.fold(() => fab as any, f => that(f(this.value)), (l, f) => both(l, f(this.value))) - } - chain(SL: Semigroup, f: (a: A) => These): These { - return f(this.value) - } bimap(f: (l: L) => M, g: (a: A) => B): These { return that(g(this.value)) } @@ -106,17 +83,6 @@ export class That fold(this_: (l: L) => B, that: (a: A) => B, both: (l: L, a: A) => B): B { return that(this.value) } - equals(setoidL: Setoid, setoidA: Setoid): (fy: These) => boolean { - return fy => fy.fold(constFalse, a => setoidA.equals(a)(this.value), constFalse) - } - concat(SL: Semigroup, SA: Semigroup): (fy: These) => These { - return fy => - fy.fold( - l => both(l, this.value), - a => that(SA.concat(this.value)(a)), - (l, a) => both(l, SA.concat(this.value)(a)) - ) - } inspect() { return this.toString() } @@ -135,16 +101,6 @@ export class Both map(f: (a: A) => B): These { return new Both(this.l, f(this.a)) } - ap(SL: Semigroup, fab: These B>): These { - return fab.fold(() => fab as any, f => both(this.l, f(this.a)), (l, f) => both(SL.concat(l)(this.l), f(this.a))) - } - chain(SL: Semigroup, f: (a: A) => These): These { - return f(this.a).fold( - l => this_(SL.concat(this.l)(l)), - a => both(this.l, a), - (l, a) => both(SL.concat(this.l)(l), a) - ) - } bimap(f: (l: L) => M, g: (a: A) => B): These { return both(f(this.l), g(this.a)) } @@ -160,17 +116,6 @@ export class Both fold(this_: (l: L) => B, that: (a: A) => B, both: (l: L, a: A) => B): B { return both(this.l, this.a) } - equals(setoidL: Setoid, setoidA: Setoid): (fy: These) => boolean { - return fy => fy.fold(constFalse, constFalse, (l, a) => setoidL.equals(l)(this.l) && setoidA.equals(a)(this.a)) - } - concat(SL: Semigroup, SA: Semigroup): (fy: These) => These { - return fy => - fy.fold( - l => both(SL.concat(this.l)(l), this.a), - a => both(this.l, SA.concat(this.a)(a)), - (l, a) => both(SL.concat(this.l)(l), SA.concat(this.a)(a)) - ) - } inspect() { return this.toString() } @@ -179,45 +124,55 @@ export class Both } } -export const equals = (SL: Setoid, SA: Setoid) => (fx: These) => (fy: These): boolean => - fx.equals(SL, SA)(fy) +export const fold = (this_: (l: L) => B, that: (a: A) => B, both: (l: L, a: A) => B) => (fa: These): B => + fa.fold(this_, that, both) export const getSetoid = (SL: Setoid, SA: Setoid): Setoid> => ({ - equals: equals(SL, SA) + equals: x => y => + x.fold( + lx => y.fold(ly => SL.equals(lx)(ly), constFalse, constFalse), + ax => y.fold(constFalse, ay => SA.equals(ax)(ay), constFalse), + (lx, ax) => y.fold(constFalse, constFalse, (ly, ay) => SL.equals(lx)(ly) && SA.equals(ax)(ay)) + ) }) -export const concat = (SL: Semigroup, SA: Semigroup) => (fx: These) => ( - fy: These -): These => fx.concat(SL, SA)(fy) - export const getSemigroup = (SL: Semigroup, SA: Semigroup): Semigroup> => ({ - concat: concat(SL, SA) + concat: x => y => + x.fold( + lx => y.fold(ly => this_(SL.concat(lx)(ly)), ay => both(lx, ay), (ly, ay) => both(SL.concat(lx)(ly), ay)), + ax => y.fold(lx => both(lx, ax), ay => that(SA.concat(ax)(ay)), (ly, ay) => both(ly, SA.concat(ax)(ay))), + (lx, ax) => + y.fold( + ly => both(SL.concat(lx)(ly), ax), + ay => both(lx, SA.concat(ax)(ay)), + (ly, ay) => both(SL.concat(lx)(ly), SA.concat(ax)(ay)) + ) + ) }) -export const fold = (this_: (l: L) => B, that: (a: A) => B, both: (l: L, a: A) => B, fa: These): B => - fa.fold(this_, that, both) - export const map = (f: (a: A) => B, fa: These): These => fa.map(f) export const of = (a: A): These => new That(a) -/** deprecated */ -export const ap = (SL: Semigroup, fab: These B>, fa: These): These => - fa.ap(SL, fab) +export const ap = (S: Semigroup) => (fab: These B>, fa: These) => + chain(S)(f => map(f, fa), fab) -/** deprecated */ -export const chain = (SL: Semigroup, f: (a: A) => These, fa: These): These => - fa.chain(SL, f) +export const chain = (S: Semigroup) => (f: (a: A) => These, fa: These): These => + fa.fold( + () => fa as any, + a => f(a), + (l1, a) => f(a).fold(l2 => this_(S.concat(l1)(l2)), b => both(l1, b), (l2, b) => both(S.concat(l1)(l2), b)) + ) -export const getMonad = (SL: Semigroup): Monad => ({ +export const getMonad = (S: Semigroup): Monad => ({ URI, map, of, - ap: (fab: These B>, fa: These) => fa.ap(SL, fab), - chain: (f: (a: A) => These, fa: These) => fa.chain(SL, f) + ap: ap(S), + chain: chain(S) }) -export const bimap = (f: (l: L) => M, g: (a: A) => B) => (fla: These): These => fla.bimap(f, g) +export const bimap = (f: (l: L) => M, g: (a: A) => B, fla: These): These => fla.bimap(f, g) export const reduce = (f: (b: B, a: A) => B, b: B, fa: These): B => fa.reduce(f, b) @@ -228,7 +183,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKTAs, ta: These) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: These) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: These) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/Trace.ts b/src/Trace.ts index c6a84b492..bd5561258 100644 --- a/src/Trace.ts +++ b/src/Trace.ts @@ -5,7 +5,8 @@ import { Monad } from './Monad' // Adapted from https://github.com/garyb/purescript-debug -/** Log any value to the console for debugging purposes and then +/** + * Log any value to the console for debugging purposes and then * return a value. This will log the value's underlying representation for * low-level debugging */ @@ -18,7 +19,8 @@ export const trace = (message: any, out: Lazy): A => { export const spy = (a: A): A => trace(a, () => a) export class Ops { - /** Log a message to the console for debugging purposes and then return the + /** + * Log a message to the console for debugging purposes and then return the * unit value of the Applicative `F` */ traceA(F: Applicative): (message: any) => HKT2As @@ -28,7 +30,8 @@ export class Ops { return x => trace(x, () => F.of(undefined)) } - /** Log any value to the console and return it in `Monad` + /** + * Log any value to the console and return it in `Monad` * useful when one has monadic chains */ traceM(F: Monad): (a: A) => HKT2As diff --git a/src/Traversable.ts b/src/Traversable.ts index 05e9b8933..85a8d54cd 100644 --- a/src/Traversable.ts +++ b/src/Traversable.ts @@ -1,4 +1,4 @@ -import { HKT, HKTS, HKT2S, HKTAs, HKT2As } from './HKT' +import { HKT, HKTS, HKT2S, HKTAs, HKT2As, HKT3S, HKT3As } from './HKT' import { Functor, FantasyFunctor, FunctorComposition, getFunctorComposition } from './Functor' import { Foldable, FantasyFoldable, FoldableComposition, getFoldableComposition } from './Foldable' import { Applicative } from './Applicative' @@ -29,6 +29,10 @@ export interface TraversableComposition11 } export class Ops { + sequence( + F: Applicative, + T: Traversable + ): (tfa: HKTAs>) => HKT3As> sequence( F: Applicative, T: Traversable diff --git a/src/Tuple.ts b/src/Tuple.ts index 56aa56184..d66a6424f 100644 --- a/src/Tuple.ts +++ b/src/Tuple.ts @@ -11,12 +11,12 @@ import { Foldable, FantasyFoldable } from './Foldable' import { Applicative } from './Applicative' import { Traversable, FantasyTraversable } from './Traversable' import { Semigroupoid, FantasySemigroupoid } from './Semigroupoid' -import { Cokleisli, toString } from './function' +import { toString } from './function' import { ChainRec } from './ChainRec' import { Chain } from './Chain' import { Either, isLeft, Right, Left } from './Either' -// https://github.com/purescript/purescript-tuples +// Adapted from https://github.com/purescript/purescript-tuples declare module './HKT' { interface URI2HKT2 { @@ -56,7 +56,7 @@ export class Tuple extract(): A { return this.snd() } - extend(f: Cokleisli): Tuple { + extend(f: (fa: Tuple) => B): Tuple { return new Tuple([this.fst(), f(this)]) } reduce(f: (c: B, b: A) => B, c: B): B { @@ -79,18 +79,17 @@ export const fst = (fa: Tuple): L => fa.fst() /** Returns the second component of a tuple. */ export const snd = (fa: Tuple): A => fa.snd() -export const compose = (bc: Tuple) => (fa: Tuple): Tuple => { +export const compose = (bc: Tuple, fa: Tuple): Tuple => { return fa.compose(bc) } export const map = (f: (b: A) => B, fa: Tuple): Tuple => fa.map(f) -export const bimap = (f: (l: L) => M, g: (a: A) => B): ((fla: Tuple) => Tuple) => fla => - fla.bimap(f, g) +export const bimap = (f: (l: L) => M, g: (a: A) => B, fla: Tuple): Tuple => fla.bimap(f, g) export const extract = snd -export const extend = (f: Cokleisli, fa: Tuple): Tuple => fa.extend(f) +export const extend = (f: (fa: Tuple) => B, fa: Tuple): Tuple => fa.extend(f) export const reduce = (f: (c: B, b: A) => B, c: B, fa: Tuple): B => fa.reduce(f, c) @@ -106,60 +105,55 @@ export const getSetoid = (SA: Setoid, SB: Setoid): Setoid(OA: Ord, OB: Ord): Ord> => - getOrdSemigroup>().concat(contramapOrd(fst, OA))(contramapOrd(snd, OB)) +export const getOrd = (OL: Ord, OA: Ord): Ord> => + getOrdSemigroup>().concat(contramapOrd(fst, OL))(contramapOrd(snd, OA)) -export const getSemigroup = (SA: Semigroup, SB: Semigroup): Semigroup> => ({ +export const getSemigroup = (SL: Semigroup, SA: Semigroup): Semigroup> => ({ concat: x => y => { const [xa, xb] = x.value const [ya, yb] = y.value - return new Tuple([SA.concat(xa)(ya), SB.concat(xb)(yb)]) + return new Tuple([SL.concat(xa)(ya), SA.concat(xb)(yb)]) } }) -export const getMonoid = (MA: Monoid, MB: Monoid): Monoid> => { - const empty = new Tuple([MA.empty(), MB.empty()]) +export const getMonoid = (ML: Monoid, MA: Monoid): Monoid> => { + const empty = new Tuple([ML.empty(), MA.empty()]) return { - ...getSemigroup(MA, MB), + ...getSemigroup(ML, MA), empty: () => empty } } +export const ap = (S: Semigroup) => (fab: Tuple B>, fa: Tuple): Tuple => + new Tuple([S.concat(fa.fst())(fab.fst()), fab.snd()(fa.snd())]) + export const getApply = (S: Semigroup): Apply => ({ URI, map, - ap(fab: Tuple B>, fa: Tuple): Tuple { - return new Tuple([S.concat(fa.fst())(fab.fst()), fab.snd()(fa.snd())]) - } + ap: ap(S) }) -export const getApplicative = (monoidA: Monoid): Applicative => { - const empty = monoidA.empty() - return { - ...getApply(monoidA), - of(a: A): Tuple { - return new Tuple([empty, a]) - } - } +export const of = (M: Monoid) => (a: A): Tuple => new Tuple([M.empty(), a]) + +export const getApplicative = (M: Monoid): Applicative => ({ + ...getApply(M), + of: of(M) +}) + +export const chain = (M: Monoid) => (f: (b: A) => Tuple, fa: Tuple): Tuple => { + const lb = f(fa.snd()) + return new Tuple([M.concat(fa.fst())(lb.fst()), lb.snd()]) } export const getChain = (M: Monoid): Chain => ({ ...getApply(M), - chain(f: (b: A) => Tuple, fa: Tuple): Tuple { - const lb = f(fa.snd()) - return new Tuple([M.concat(fa.fst())(lb.fst()), lb.snd()]) - } + chain: chain(M) }) -export const getMonad = (M: Monoid): Monad => { - const empty = M.empty() - return { - ...getChain(M), - of(b: B): Tuple { - return new Tuple([empty, b]) - } - } -} +export const getMonad = (M: Monoid): Monad => ({ + ...getChain(M), + of: of(M) +}) export const chainRec = (M: Monoid) => (f: (a: A) => Tuple>, a: A): Tuple => { let result = f(a) @@ -183,7 +177,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKTAs, ta: Tuple) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Tuple) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Tuple) => HKT> { return (f, ta) => ta.traverse(F)(f) } diff --git a/src/Unfoldable.ts b/src/Unfoldable.ts index 6846a9a24..5a2e70964 100644 --- a/src/Unfoldable.ts +++ b/src/Unfoldable.ts @@ -1,4 +1,4 @@ -import { HKT } from './HKT' +import { HKT, HKTS, HKTAs, HKT2S, HKT2As, HKT3S, HKT3As } from './HKT' import { Applicative } from './Applicative' import { Traversable } from './Traversable' import * as option from './Option' @@ -21,14 +21,32 @@ export const replicate = (unfoldable: Unfoldable) => (n: number) => (a: return unfoldable.unfoldr(step, n) } -/** Perform an Applicative action `n` times, and accumulate all the results. */ -export const replicateA = ( - applicative: Applicative, - unfoldableTraversable: Unfoldable & Traversable -) => (n: number) => (ma: HKT): HKT> => - sequence(applicative, unfoldableTraversable)(replicate(unfoldableTraversable)(n)(ma)) - /** The container with no elements - unfolded with zero iterations. */ export const none = (unfoldable: Unfoldable): HKT => unfoldable.unfoldr(constant(option.none), undefined) export const singleton = (unfoldable: Unfoldable) => (a: A): HKT => replicate(unfoldable)(1)(a) + +export class Ops { + /** Perform an Applicative action `n` times, and accumulate all the results. */ + replicateA( + applicative: Applicative, + unfoldableTraversable: Unfoldable & Traversable + ): (n: number) => (ma: HKT3As) => HKT3As> + replicateA( + applicative: Applicative, + unfoldableTraversable: Unfoldable & Traversable + ): (n: number) => (ma: HKT2As) => HKT2As> + replicateA( + applicative: Applicative, + unfoldableTraversable: Unfoldable & Traversable + ): (n: number) => (ma: HKTAs) => HKTAs> + replicateA( + applicative: Applicative, + unfoldableTraversable: Unfoldable & Traversable + ): (n: number) => (ma: HKT) => HKT> { + return n => ma => sequence(applicative, unfoldableTraversable)(replicate(unfoldableTraversable)(n)(ma)) + } +} + +const ops = new Ops() +export const replicateA: Ops['replicateA'] = ops.replicateA diff --git a/src/Validation.ts b/src/Validation.ts index 2722124f7..d2aa05c09 100644 --- a/src/Validation.ts +++ b/src/Validation.ts @@ -10,7 +10,6 @@ import { Alt, FantasyAlt } from './Alt' import { constFalse, Predicate, toString } from './function' import { Option, some, none } from './Option' import { Either, left, right } from './Either' -import * as nonEmptyArray from './NonEmptyArray' declare module './HKT' { interface URI2HKT2 { @@ -80,10 +79,6 @@ export class Failure toEither(): Either { return left(this.value) } - /** Lift the Invalid value into a NonEmptyArray */ - toValidationNea(): Option, A>> { - return some(failure(nonEmptyArray)(nonEmptyArray.of(this.value))) - } inspect() { return this.toString() } @@ -147,10 +142,6 @@ export class Success toEither(): Either { return right(this.value) } - /** Lift the Invalid value into a NonEmptyArray */ - toValidationNea(): Option, A>> { - return none - } inspect() { return this.toString() } @@ -159,17 +150,14 @@ export class Success } } -export const equals = (SL: Setoid, SA: Setoid) => (fx: Validation) => ( - fy: Validation -): boolean => fx.equals(SL, SA)(fy) +export const fold = (failure: (l: L) => B, success: (a: A) => B) => (fa: Validation): B => + fa.fold(failure, success) export const getSetoid = (SL: Setoid, SA: Setoid): Setoid> => ({ - equals: equals(SL, SA) + equals: x => y => + x.fold(lx => y.fold(ly => SL.equals(lx)(ly), constFalse), ax => y.fold(constFalse, ay => SA.equals(ax)(ay))) }) -export const fold = (failure: (l: L) => B, success: (a: A) => B, fa: Validation): B => - fa.fold(failure, success) - export const map = (f: (a: A) => B, fa: Validation): Validation => fa.map(f) export const of = (a: A): Validation => new Success(a) @@ -180,7 +168,7 @@ export const bimap = (S: Semigroup) => (f: (l: L) => M, g: (a: A) fa: Validation ): Validation => fa.bimap(S)(f, g) -export const alt = (fx: Validation) => (fy: Validation): Validation => fx.alt(fy) +export const alt = (fx: Validation, fy: Validation): Validation => fx.alt(fy) export const reduce = (f: (b: B, a: A) => B, b: B, fa: Validation): B => fa.reduce(f, b) @@ -191,7 +179,7 @@ export class Ops { traverse( F: Applicative ): (f: (a: A) => HKTAs, ta: Validation) => HKTAs> - traverse(F: Applicative): (f: (a: A) => HKT, ta: Validation) => HKT> + traverse(F: Applicative): (f: (a: A) => HKT, ta: HKT) => HKT> traverse(F: Applicative): (f: (a: A) => HKT, ta: Validation) => HKT> { return (f, ta) => ta.traverse(F)(f) } @@ -228,9 +216,6 @@ export const toOption = (fa: Validation): Option => fa.toOption() export const toEither = (fa: Validation): Either => fa.toEither() -export const toValidationNea = (fa: Validation): Option, A>> => - fa.toValidationNea() - export const validation: Semigroup> & Functor & Applicative & diff --git a/src/Witherable.ts b/src/Witherable.ts deleted file mode 100644 index 7f5bdf967..000000000 --- a/src/Witherable.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { HKT, HKTS, HKTAs } from './HKT' -import { Traversable, FantasyTraversable } from './Traversable' -import { Filterable, FantasyFilterable } from './Filterable' -import { Applicative } from './Applicative' -import { Either, left, right } from './Either' -import { Option } from './Option' - -export type Wilt = { - left: HKT - right: HKT -} - -export type Wilt1 = { - left: HKTAs - right: HKTAs -} - -export interface Witherable extends Traversable, Filterable { - wilt: (F: Applicative) => (f: (a: A) => HKT>, ta: HKT) => HKT> -} - -export interface FantasyWitherable extends FantasyTraversable, FantasyFilterable { - wilt: (F: Applicative) => (f: (a: A) => HKT>) => HKT> -} - -export class Ops { - /** A default implementation of `wither` using `wilt` */ - wither( - F: Applicative, - T: Witherable - ): (f: (a: A) => HKT>, ta: HKT) => HKTAs> - wither( - F: Applicative, - T: Witherable - ): (f: (a: A) => HKT>, ta: HKT) => HKT> - wither( - F: Applicative, - T: Witherable - ): (f: (a: A) => HKT>, ta: HKT) => HKT> { - return (f: (a: A) => HKT>, ta: HKT): HKT> => { - const mb: HKT> = T.wilt(F)( - a => F.map(ob => ob.fold(() => left(null), b => right(b)), f(a)), - ta - ) - return F.map(w => w.right, mb) - } - } - - /** Partition between `Left` and `Right` values - with effects in `m` */ - wilted( - F: Applicative, - T: Witherable - ): (tm: HKT>>) => HKTAs> - wilted(F: Applicative, T: Witherable): (tm: HKT>>) => HKT> - wilted(F: Applicative, T: Witherable): (tm: HKT>>) => HKT> { - return tm => T.wilt(F)(me => me, tm) - } - - /** Filter out all the `Nothing` values - with effects in `m` */ - withered( - F: Applicative, - T: Witherable - ): (tm: HKT>>) => HKTAs> - withered(F: Applicative, T: Witherable): (tm: HKT>>) => HKT> - withered(F: Applicative, T: Witherable): (tm: HKT>>) => HKT> { - return tm => this.wither(F, T)(moa => moa, tm) - } -} - -const ops = new Ops() -export const wither: Ops['wither'] = ops.wither -export const wilted: Ops['wilted'] = ops.wilted -export const withered: Ops['withered'] = ops.withered diff --git a/src/function.ts b/src/function.ts index 76b3a643b..3f315d2b6 100644 --- a/src/function.ts +++ b/src/function.ts @@ -31,12 +31,10 @@ export type Refinement = (a: A) => a is B export const not = (predicate: Predicate): Predicate => a => !predicate(a) -export function or( - p1: Refinement -): (p2: Refinement) => Refinement -export function or(p1: Predicate): (p2: Predicate) => Predicate -export function or(p1: Predicate): (p2: Predicate) => Predicate { - return p2 => a => p1(a) || p2(a) +export function or(p1: Refinement, p2: Refinement): Refinement +export function or(p1: Predicate, p2: Predicate): Predicate +export function or(p1: Predicate, p2: Predicate): Predicate { + return a => p1(a) || p2(a) } export const and = (p1: Predicate, p2: Predicate): Predicate => a => p1(a) && p2(a) diff --git a/src/index.ts b/src/index.ts index 57049e7f7..6e22bb7dd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -34,8 +34,6 @@ import * as extend from './Extend' export { extend } import * as field from './Field' export { field } -import * as filterable from './Filterable' -export { filterable } import * as foldable from './Foldable' export { foldable } import * as free from './Free' @@ -118,7 +116,5 @@ import * as unfoldable from './Unfoldable' export { unfoldable } import * as validation from './Validation' export { validation } -import * as witherable from './Witherable' -export { witherable } import * as writer from './Writer' export { writer } diff --git a/test/Applicative.ts b/test/Applicative.ts index db0ebd969..cdea156d1 100644 --- a/test/Applicative.ts +++ b/test/Applicative.ts @@ -18,8 +18,8 @@ describe('Applicative', () => { const somefailure = [ validation.success(1), - validation.failure(monoidString)('[fail 1]'), - validation.failure(monoidString)('[fail 2]') + validation.failure(monoidString)('[fail 1]'), + validation.failure(monoidString)('[fail 2]') ].map(a => new taskValidation.TaskValidation(task.of(a))) const p1 = sequence(taskValidation, array)(allsuccess).value.run() @@ -44,9 +44,9 @@ describe('Applicative', () => { const action = new io.IO(() => { log.push('action called') }) - when(io)(false)(action).run() + when(io)(false, action).run() assert.deepEqual(log, []) - when(io)(true)(action).run() + when(io)(true, action).run() assert.deepEqual(log, ['action called']) }) }) diff --git a/test/Apply.ts b/test/Apply.ts index e9853d878..7156d751c 100644 --- a/test/Apply.ts +++ b/test/Apply.ts @@ -4,15 +4,20 @@ import * as either from '../src/Either' import { eqOptions, eqEithers } from './helpers' describe('Apply', () => { + const r1 = either.right(1) + const r2 = either.right(2) + const foo = either.left('foo') + const bar = either.left('bar') + it('applyFirst', () => { eqOptions(applyFirst(option)(option.some(5))(option.some(6)), option.some(5)) eqOptions(applyFirst(option)(option.some(5))(option.empty()), option.empty()) eqOptions(applyFirst(option)(option.empty())(option.some(6)), option.empty()) - eqEithers(applyFirst(either)(either.right(1))(either.right(2)), either.right(1)) - eqEithers(applyFirst(either)(either.left(3))(either.right(4)), either.left(3)) - eqEithers(applyFirst(either)(either.right(5))(either.left(6)), either.left(6)) - eqEithers(applyFirst(either)(either.left(7))(either.left(8)), either.left(7)) + eqEithers(applyFirst(either)(r1)(r2), r1) + eqEithers(applyFirst(either)(foo)(r1), foo) + eqEithers(applyFirst(either)(r1)(foo), foo) + eqEithers(applyFirst(either)(foo)(bar), foo) }) it('applySecond', () => { @@ -20,22 +25,22 @@ describe('Apply', () => { eqOptions(applySecond(option)(option.some(5))(option.empty()), option.empty()) eqOptions(applySecond(option)(option.empty())(option.some(6)), option.empty()) - eqEithers(applySecond(either)(either.right(1))(either.right(2)), either.right(2)) - eqEithers(applySecond(either)(either.left(3))(either.right(4)), either.left(3)) - eqEithers(applySecond(either)(either.right(5))(either.left(6)), either.left(6)) - eqEithers(applySecond(either)(either.left(7))(either.left(8)), either.left(7)) + eqEithers(applySecond(either)(r1)(r2), r2) + eqEithers(applySecond(either)(foo)(r1), foo) + eqEithers(applySecond(either)(r1)(foo), foo) + eqEithers(applySecond(either)(foo)(bar), foo) }) it('liftA2', () => { const f = (a: number) => (b: number) => a + b eqOptions(liftA2(option)(f)(option.some(2))(option.some(3)), option.some(5)) - eqEithers(liftA2(either)(f)(either.right(2))(either.right(3)), either.right(5)) + eqEithers(liftA2(either)(f)(r2)(either.right(3)), either.right(5)) }) it('liftA3', () => { const f = (a: number) => (b: number) => (c: number) => a + b + c eqOptions(liftA3(option)(f)(option.some(2))(option.some(3))(option.some(4)), option.some(9)) - eqEithers(liftA3(either)(f)(either.right(2))(either.right(3))(either.right(4)), either.right(9)) + eqEithers(liftA3(either)(f)(r2)(either.right(3))(either.right(4)), either.right(9)) }) it('liftA4', () => { @@ -43,7 +48,7 @@ describe('Apply', () => { const optionf = liftA4(option)(f) eqOptions(optionf(option.some(2))(option.some(3))(option.some(4))(option.some(5)), option.some(14)) const eitherf = liftA4(either)(f) - eqEithers(eitherf(either.right(2))(either.right(3))(either.right(4))(either.right(5)), either.right(14)) + eqEithers(eitherf(r2)(either.right(3))(either.right(4))(either.right(5)), either.right(14)) }) it('ap_', () => { diff --git a/test/Contravariant.ts b/test/Contravariant.ts index 3c97e9c7f..65080a222 100644 --- a/test/Contravariant.ts +++ b/test/Contravariant.ts @@ -17,7 +17,7 @@ class Predicate { constructor(public readonly run: (a: A) => boolean) {} } -const contramap = (fa: Predicate) => (f: (b: B) => A): Predicate => new Predicate(b => fa.run(f(b))) +const contramap = (f: (b: B) => A, fa: Predicate): Predicate => new Predicate(b => fa.run(f(b))) const predicate: Contravariant = { URI, diff --git a/test/Either.ts b/test/Either.ts index 32775dac9..8c8da9a11 100644 --- a/test/Either.ts +++ b/test/Either.ts @@ -11,9 +11,9 @@ import { fromPredicate, tryCatch, fromOption, - bimap, fromNullable, - equals + bimap, + getSetoid } from '../src/Either' import { eqEithers as eq } from './helpers' import { none, some } from '../src/Option' @@ -23,8 +23,8 @@ describe('Either', () => { it('fold', () => { const f = (s: string) => `left${s.length}` const g = (s: string) => `right${s.length}` - assert.strictEqual(fold(f, g, left('abc')), 'left3') - assert.strictEqual(fold(f, g, right('abc')), 'right3') + assert.strictEqual(fold(f, g)(left('abc')), 'left3') + assert.strictEqual(fold(f, g)(right('abc')), 'right3') }) it('map', () => { @@ -36,21 +36,21 @@ describe('Either', () => { it('bimap', () => { const f = (s: string): number => s.length const g = (n: number): boolean => n > 2 - eq(bimap(f, g)(right(1)), right(false)) + eq(bimap(f, g, right(1)), right(false)) }) it('ap', () => { const f = (s: string): number => s.length - eq(ap(right(f), right('abc')), right(3)) - eq(ap(right(f), left('s')), left('s')) - eq(ap(left(f), right('abc')), left(f)) - eq(ap(left(f), left('abc')), left(f)) + eq(ap(right number>(f), right('abc')), right(3)) + eq(ap(right number>(f), left('a')), left('a')) + eq(ap(left number>('a'), right('abc')), left('a')) + eq(ap(left number>('a'), left('b')), left('a')) }) it('chain', () => { - const f = (s: string) => right(s.length) - eq(chain(f, right('abc')), right(3)) - eq(chain(f, left('s')), left('s')) + const f = (s: string) => right(s.length) + eq(chain(f, right('abc')), right(3)) + eq(chain(f, left('a')), left('a')) }) it('fromPredicate', () => { @@ -69,12 +69,12 @@ describe('Either', () => { const e2 = tryCatch(() => { return JSON.parse(``) }) - eq(e2, left({})) + eq(e2, left(new Error())) }) it('getOrElse', () => { - assert.equal(getOrElse(() => 17)(right(12)), 12) - assert.equal(getOrElse(() => 17)(left(12)), 17) + assert.equal(getOrElse((l: number) => 17)(right(12)), 12) + assert.equal(getOrElse((l: number) => 17)(left(12)), 17) assert.equal(getOrElse((l: number) => l + 1)(left(12)), 13) }) @@ -95,7 +95,7 @@ describe('Either', () => { }) it('equals', () => { - const eq = equals(setoidString, setoidNumber) + const eq = getSetoid(setoidString, setoidNumber).equals assert.strictEqual(eq(right(1))(right(1)), true) assert.strictEqual(eq(right(1))(right(2)), false) assert.strictEqual(eq(left('foo'))(left('foo')), true) diff --git a/test/Filterable.ts b/test/Filterable.ts deleted file mode 100644 index edbbde6fe..000000000 --- a/test/Filterable.ts +++ /dev/null @@ -1,53 +0,0 @@ -import * as assert from 'assert' -import * as filterable from '../src/Filterable' -import * as array from '../src/Array' -import * as either from '../src/Either' -import * as option from '../src/Option' - -describe('Filterable', () => { - it('partitionMap', () => { - const isEven = (n: number) => n % 2 === 0 - const { left, right } = array.partitionMap( - (a: string): either.Either => (isEven(a.length) ? either.right(a) : either.left(a.length)), - ['a', 'bb', 'ccc'] - ) - assert.deepEqual(left, [1, 3]) - assert.deepEqual(right, ['bb']) - }) - - it('partition', () => { - const isEven = (n: number) => n % 2 === 0 - const { no, yes } = filterable.partition(array)(isEven)([1, 2, 3]) - assert.deepEqual(no, [1, 3]) - assert.deepEqual(yes, [2]) - }) - - it('filterMap', () => { - const xs = filterable.filterMap(array)((s: string) => (s.length >= 2 ? option.some(s.length) : option.none))([ - 'a', - 'bb', - 'ccc' - ]) - assert.deepEqual(xs, [2, 3]) - }) - - it('filter', () => { - const isEven = (n: number) => n % 2 === 0 - const xs = filterable.filter(array)(isEven)([1, 2, 3]) - assert.deepEqual(xs, [2]) - }) - - it('partitioned', () => { - const { left, right } = filterable.partitioned(array)([ - either.left('a'), - either.right(1) - ]) - assert.deepEqual(left, ['a']) - assert.deepEqual(right, [1]) - }) - - it('filtered', () => { - const xs = filterable.filtered(array)([option.some(1), option.none] as Array>) - assert.deepEqual(xs, [1]) - }) -}) diff --git a/test/Monoidal.ts b/test/Monoidal.ts index 15f4c6fa1..c31c9ab32 100644 --- a/test/Monoidal.ts +++ b/test/Monoidal.ts @@ -6,11 +6,11 @@ import * as either from '../src/Either' describe('Monoidal', () => { it('fromApplicative', () => { const monoidalOption = fromApplicative(option) - assert.deepEqual(monoidalOption.mult(option.some(1))(option.some('a')), option.some([1, 'a'])) - assert.deepEqual(monoidalOption.mult(option.some(1))(option.none), option.none) + assert.deepEqual(monoidalOption.mult(option.some(1), option.some('a')), option.some([1, 'a'])) + assert.deepEqual(monoidalOption.mult(option.some(1), option.none), option.none) const monoidalEither = fromApplicative(either) - assert.deepEqual(monoidalEither.mult(either.right(1))(either.right('a')), either.right([1, 'a'])) - assert.deepEqual(monoidalEither.mult(either.right(1))(either.left('error')), either.left('error')) + assert.deepEqual(monoidalEither.mult(either.right(1), either.right('a')), either.right([1, 'a'])) + assert.deepEqual(monoidalEither.mult(either.right(1), either.left('error')), either.left('error')) }) it('toApplicative', () => { diff --git a/test/Option.ts b/test/Option.ts index 2ac5ace76..586076c32 100644 --- a/test/Option.ts +++ b/test/Option.ts @@ -1,6 +1,6 @@ import * as assert from 'assert' import { - equals, + getSetoid, fold, none, map, @@ -23,8 +23,8 @@ describe('Option', () => { it('fold', () => { const f = () => 'none' const g = (s: string) => `some${s.length}` - assert.strictEqual(fold(f, g, none), 'none') - assert.strictEqual(fold(f, g, some('abc')), 'some3') + assert.strictEqual(fold(f, g)(none), 'none') + assert.strictEqual(fold(f, g)(some('abc')), 'some3') }) it('getOrElse', () => { @@ -42,11 +42,11 @@ describe('Option', () => { }) it('equals', () => { - const eq = equals(setoidNumber) - assert.strictEqual(eq(none)(none), true) - assert.strictEqual(eq(none)(some(1)), false) - assert.strictEqual(eq(some(2))(some(1)), false) - assert.strictEqual(eq(some(2))(some(2)), true) + const { equals } = getSetoid(setoidNumber) + assert.strictEqual(equals(none)(none), true) + assert.strictEqual(equals(none)(some(1)), false) + assert.strictEqual(equals(some(2))(some(1)), false) + assert.strictEqual(equals(some(2))(some(2)), true) }) it('map', () => { @@ -98,10 +98,10 @@ describe('Option', () => { }) it('alt', () => { - eq(alt(some(1))(some(2)), some(1)) - eq(alt(none)(some(2)), some(2)) - eq(alt(some(1))(none), some(1)) - eq(alt(none)(none), none) + eq(alt(some(1), some(2)), some(1)) + eq(alt(none, some(2)), some(2)) + eq(alt(some(1), none), some(1)) + eq(alt(none, none), none) }) it('fromNullable', () => { diff --git a/test/These.ts b/test/These.ts index 5b83d3b6f..42af068d7 100644 --- a/test/These.ts +++ b/test/These.ts @@ -1,55 +1,34 @@ import * as assert from 'assert' -import { this_, that, both, fromThese, bimap } from '../src/These' +import { this_, that, both, fromThese, bimap, getSetoid, getSemigroup } from '../src/These' import { setoidNumber, setoidString } from '../src/Setoid' import { monoidSum, monoidString } from '../src/Monoid' describe('These', () => { it('equals', () => { - assert.strictEqual(this_(2).equals(setoidNumber, setoidNumber)(this_(2)), true) - assert.strictEqual(this_(2).equals(setoidNumber, setoidNumber)(this_(3)), false) + const { equals } = getSetoid(setoidNumber, setoidNumber) + assert.strictEqual(equals(this_(2))(this_(2)), true) + assert.strictEqual(equals(this_(2))(this_(3)), false) }) it('concat', () => { - assert.strictEqual( - this_('a').concat(monoidString, monoidSum)(this_('b')).equals(setoidString, setoidNumber)( - this_('ab') - ), - true - ) - assert.strictEqual( - this_('a').concat(monoidString, monoidSum)(that(2)).equals(setoidString, setoidNumber)( - both('a', 2) - ), - true - ) + const { equals } = getSetoid(setoidString, setoidNumber) + const { concat } = getSemigroup(monoidString, monoidSum) + assert.strictEqual(equals(concat(this_('a'))(this_('b')))(this_('ab')), true) + assert.strictEqual(equals(concat(this_('a'))(that(2)))(both('a', 2)), true) }) it('map', () => { + const { equals } = getSetoid(setoidNumber, setoidNumber) const double = (n: number) => n * 2 - assert.strictEqual( - this_(2) - .map(double) - .equals(setoidNumber, setoidNumber)(this_(2)), - true - ) - assert.strictEqual( - that(2) - .map(double) - .equals(setoidNumber, setoidNumber)(that(4)), - true - ) - assert.strictEqual( - both(1, 2) - .map(double) - .equals(setoidNumber, setoidNumber)(both(1, 4)), - true - ) + assert.strictEqual(equals(this_(2).map(double))(this_(2)), true) + assert.strictEqual(equals(that(2).map(double))(that(4)), true) + assert.strictEqual(equals(both(1, 2).map(double))(both(1, 4)), true) }) it('bimap', () => { const len = (s: string): number => s.length const double = (n: number): number => n * 2 - assert.deepEqual(bimap(len, double)(both('foo', 1)), both(3, 2)) + assert.deepEqual(bimap(len, double, both('foo', 1)), both(3, 2)) }) it('fromThese', () => { @@ -60,19 +39,10 @@ describe('These', () => { }) it('bimap', () => { + const { equals } = getSetoid(setoidNumber, setoidNumber) const double = (n: number) => n * 2 const len = (s: string) => s.length - assert.strictEqual( - this_('a') - .bimap(len, double) - .equals(setoidNumber, setoidNumber)(this_(1)), - true - ) - assert.strictEqual( - that(2) - .bimap(len, double) - .equals(setoidNumber, setoidNumber)(that(4)), - true - ) + assert.strictEqual(equals(this_('a').bimap(len, double))(this_(1)), true) + assert.strictEqual(equals(that(2).bimap(len, double))(that(4)), true) }) }) diff --git a/test/Tuple.ts b/test/Tuple.ts index c74162c0d..228ca7552 100644 --- a/test/Tuple.ts +++ b/test/Tuple.ts @@ -7,7 +7,7 @@ import { sort } from '../src/Array' describe('Tuple', () => { it('compose', () => { - assert.deepEqual(compose(new Tuple([1, 's']))(new Tuple([true, 2])), new Tuple([true, 's'])) + assert.deepEqual(compose(new Tuple([1, 's']), new Tuple([true, 2])), new Tuple([true, 's'])) }) it('map', () => { @@ -18,7 +18,7 @@ describe('Tuple', () => { it('bimap', () => { const double = (n: number): number => n * 2 const len = (s: string): number => s.length - assert.deepEqual(bimap(len, double)(new Tuple(['s', 1])), new Tuple([1, 2])) + assert.deepEqual(bimap(len, double, new Tuple(['s', 1])), new Tuple([1, 2])) }) it('getSemigroup', () => { diff --git a/test/Unfoldable.ts b/test/Unfoldable.ts index 9a2a80d1a..22b0c4a74 100644 --- a/test/Unfoldable.ts +++ b/test/Unfoldable.ts @@ -1,16 +1,16 @@ -// import * as assert from 'assert' +import * as assert from 'assert' -// import { replicate, replicateA } from '../src/Unfoldable' -// import * as array from '../src/Array' -// import * as option from '../src/Option' -// import { eqOptions as eq } from './helpers' +import { replicate, replicateA } from '../src/Unfoldable' +import * as array from '../src/Array' +import * as option from '../src/Option' +import { eqOptions as eq } from './helpers' -// describe('Unfoldable', () => { -// it('replicate', () => { -// assert.deepEqual(replicate(array)(2, 's'), ['s', 's']) -// }) +describe('Unfoldable', () => { + it('replicate', () => { + assert.deepEqual(replicate(array)(2)('s'), ['s', 's']) + }) -// it('replicateA', () => { -// eq(replicateA(option, array)(2, option.some(1)), option.some([1, 1])) -// }) -// }) + it('replicateA', () => { + eq(replicateA(option, array)(2)(option.some(1)), option.some([1, 1])) + }) +}) diff --git a/test/Validation.ts b/test/Validation.ts index a12b460a7..aa3a43751 100644 --- a/test/Validation.ts +++ b/test/Validation.ts @@ -45,7 +45,7 @@ describe('Validation', () => { it('equals', () => { const failure = validation.failure(monoidString) - const eq = validation.equals(setoidString, setoidNumber) + const eq = validation.getSetoid(setoidString, setoidNumber).equals assert.strictEqual(eq(validation.success(1))(validation.success(1)), true) assert.strictEqual(eq(validation.success(1))(validation.success(2)), false) assert.strictEqual(eq(failure('foo'))(failure('foo')), true) diff --git a/test/Witherable.ts b/test/Witherable.ts deleted file mode 100644 index 6d071321d..000000000 --- a/test/Witherable.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as assert from 'assert' -import * as witherable from '../src/Witherable' -import * as array from '../src/Array' -import * as option from '../src/Option' -import * as identity from '../src/Identity' - -describe('Witherable', () => { - it('Array/wither', () => { - const f = (n: number): identity.Identity> => - n > 5 ? identity.of(option.some(n * 10)) : identity.of(option.none) - assert.deepEqual(witherable.wither(identity, array)(f, [1, 2, 3]).value, []) - assert.deepEqual(witherable.wither(identity, array)(f, [1, 2, 6]).value, [60]) - }) - - it('Option/wither', () => { - const f = (n: number): identity.Identity> => - n > 5 ? identity.of(option.some(n * 10)) : identity.of(option.none) - assert.deepEqual(witherable.wither(identity, option)(f, option.some(6)).value, option.some(60)) - assert.deepEqual(witherable.wither(identity, option)(f, option.some(5)).value, option.none) - assert.deepEqual(witherable.wither(identity, option)(f, option.none).value, option.none) - }) - - it('withered', () => { - assert.deepEqual( - witherable.withered(identity, array)([identity.of(option.none), identity.of(option.some(1))]).value, - [1] - ) - }) -}) diff --git a/test/function.ts b/test/function.ts index cc2d15892..28e86c0eb 100644 --- a/test/function.ts +++ b/test/function.ts @@ -53,7 +53,7 @@ describe('function', () => { // as predicate const gt3 = (n: number) => n > 3 const lt2 = (n: number) => n < 2 - const outside2and3 = or(lt2)(gt3) + const outside2and3 = or(lt2, gt3) assert.strictEqual(outside2and3(1), true) assert.strictEqual(outside2and3(4), true) assert.strictEqual(outside2and3(2.5), false) @@ -68,7 +68,7 @@ describe('function', () => { } const isB = (a: A): a is B => a instanceof B const isC = (a: A): a is C => a instanceof C - const isBOrC = or(isB)(isC) + const isBOrC = or(isB, isC) function f(a: any): 'B' | 'C' | 'else' { if (isBOrC(a)) { return a._tag