Skip to content

Commit

Permalink
add readerTask & getReaderTaskValidation
Browse files Browse the repository at this point in the history
  • Loading branch information
sledorze authored and gcanti committed Dec 6, 2019
1 parent e47c98f commit 6168985
Show file tree
Hide file tree
Showing 5 changed files with 403 additions and 6 deletions.
164 changes: 164 additions & 0 deletions src/ReaderTask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { IO } from './IO'
import { Monad2 } from './Monad'
import { MonadTask2 } from './MonadTask'
import { Monoid } from './Monoid'
import { pipeable } from './pipeable'
import { getSemigroup as getReaderSemigroup, Reader } from './Reader'
import { getReaderM } from './ReaderT'
import { Semigroup } from './Semigroup'
import * as TA from './Task'

import Task = TA.Task

const T = getReaderM(TA.task)

declare module './HKT' {
interface URItoKind2<E, A> {
ReaderTask: ReaderTask<E, A>
}
}

/**
* @since 2.3.0
*/
export const URI = 'ReaderTask'

/**
* @since 2.3.0
*/
export type URI = typeof URI

/**
* @since 2.3.0
*/
export interface ReaderTask<R, A> {
(r: R): Task<A>
}

/**
* @since 2.3.0
*/
export function run<R, A>(ma: ReaderTask<R, A>, r: R): Promise<A> {
return ma(r)()
}

/**
* @since 2.3.0
*/
export const fromTask: <R, A>(ma: Task<A>) => ReaderTask<R, A> = T.fromM

/**
* @since 2.3.0
*/
export const reader: <R, A = never>(ma: Reader<R, A>) => ReaderTask<R, A> = T.fromReader

/**
* @since 2.3.0
*/
export function fromIO<R, A>(ma: IO<A>): ReaderTask<R, A> {
return fromTask(TA.fromIO(ma))
}

/**
* @since 2.3.0
*/
export function of<R, A>(a: A): ReaderTask<R, A> {
return fromTask(TA.of(a))
}

/**
* @since 2.3.0
*/
export function fromReader<R, A>(ma: Reader<R, A>): ReaderTask<R, A> {
return r => TA.of(ma(r))
}

/**
* @since 2.3.0
*/
export function getSemigroup<R, A>(S: Semigroup<A>): Semigroup<ReaderTask<R, A>> {
return getReaderSemigroup(TA.getSemigroup<A>(S))
}

/**
* @since 2.3.0
*/
export function getMonoid<R, A>(M: Monoid<A>): Monoid<ReaderTask<R, A>> {
return {
concat: getSemigroup<R, A>(M).concat,
empty: of(M.empty)
}
}

/**
* @since 2.3.0
*/
export const ask: <R>() => ReaderTask<R, R> = T.ask

/**
* @since 2.3.0
*/
export const asks: <R, A = never>(f: (r: R) => A) => ReaderTask<R, A> = T.asks

/**
* @since 2.3.0
*/
export function local<Q, R>(f: (f: Q) => R): <E, A>(ma: ReaderTask<R, A>) => ReaderTask<Q, A> {
return ma => T.local(ma, f)
}

/**
* @since 2.3.0
*/

export const readerTask: Monad2<URI> & MonadTask2<URI> = {
URI,
map: T.map,
of,
ap: T.ap,
chain: T.chain,
fromIO,
fromTask
}

/**
* Like `readerTask` but `ap` is sequential
* @since 2.3.0
*/
export const readerTaskSeq: typeof readerTask = {
...readerTask,
ap: (mab, ma) => T.chain(mab, f => T.map(ma, f))
}

const { ap, apFirst, apSecond, chain, chainFirst, flatten, map } = pipeable(readerTask)

export {
/**
* @since 2.3.0
*/
ap,
/**
* @since 2.3.0
*/
apFirst,
/**
* @since 2.3.0
*/
apSecond,
/**
* @since 2.3.0
*/
chain,
/**
* @since 2.3.0
*/
chainFirst,
/**
* @since 2.3.0
*/
flatten,
/**
* @since 2.3.0
*/
map
}
31 changes: 26 additions & 5 deletions src/ReaderTaskEither.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Alt3 } from './Alt'
import { Bifunctor3 } from './Bifunctor'
import { Alt3, Alt3C } from './Alt'
import { Bifunctor3, Bifunctor3C } from './Bifunctor'
import { Either } from './Either'
import { IO } from './IO'
import { IOEither } from './IOEither'
import { Monad3 } from './Monad'
import { MonadTask3 } from './MonadTask'
import { MonadThrow3 } from './MonadThrow'
import { Monad3, Monad3C } from './Monad'
import { MonadTask3, MonadTask3C } from './MonadTask'
import { MonadThrow3, MonadThrow3C } from './MonadThrow'
import { Monoid } from './Monoid'
import { pipe, pipeable } from './pipeable'
import { getSemigroup as getReaderSemigroup, Reader } from './Reader'
Expand All @@ -16,6 +16,8 @@ import { Task } from './Task'
import * as TE from './TaskEither'

import TaskEither = TE.TaskEither
import { readerTask } from './ReaderTask'
import { getValidationM } from './ValidationT'

const T = getReaderM(TE.taskEither)

Expand Down Expand Up @@ -224,6 +226,25 @@ export function bracket<R, E, A, B>(
)
}

/**
* @since 2.3.0
*/
export function getReaderTaskValidation<E>(
S: Semigroup<E>
): Monad3C<URI, E> & Bifunctor3C<URI, E> & Alt3C<URI, E> & MonadTask3C<URI, E> & MonadThrow3C<URI, E> {
const T = getValidationM(S, readerTask)
return {
URI,
_E: undefined as any,
fromIO: rightIO,
fromTask: rightTask,
throwError: left,
bimap: (ma, f, g) => e => TE.taskEither.bimap(ma(e), f, g),
mapLeft: (ma, f) => e => TE.taskEither.mapLeft(ma(e), f),
...T
}
}

/**
* @since 2.0.0
*/
Expand Down
5 changes: 5 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import * as random from './Random'
import * as reader from './Reader'
import * as readerEither from './ReaderEither'
import * as readerT from './ReaderT'
import * as readerTask from './ReaderTask'
import * as readerTaskEither from './ReaderTaskEither'
import * as record from './Record'
import * as ring from './Ring'
Expand Down Expand Up @@ -349,6 +350,10 @@ export {
* @since 2.0.0
*/
readerTaskEither,
/**
* @since 2.3.0
*/
readerTask,
/**
* @since 2.0.0
*/
Expand Down
128 changes: 128 additions & 0 deletions test/ReaderTask.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import * as assert from 'assert'
import { array } from '../src/Array'
import { pipe } from '../src/pipeable'
import { reader } from '../src/Reader'
import * as _ from '../src/ReaderTask'
import { task } from '../src/Task'
import { monoidString } from '../src/Monoid'
import { semigroupString } from '../src/Semigroup'

describe('ReaderTask', () => {
describe('Monad', () => {
it('map', async () => {
const double = (n: number): number => n * 2
const x = await _.run(_.readerTask.map(_.of(1), double), {})
assert.deepStrictEqual(x, 2)
})

it('ap', async () => {
const double = (n: number): number => n * 2
const mab = _.of(double)
const ma = _.of(1)
const x = await _.run(_.readerTask.ap(mab, ma), {})
assert.deepStrictEqual(x, 2)
})

it('chain', async () => {
const f = (a: string) => _.of(a.length)
const e1 = await _.run(_.readerTask.chain(_.of('foo'), f), {})
assert.deepStrictEqual(e1, 3)
})

describe('readerTaskSeq', () => {
it('chain ', async () => {
const f = (a: string) => _.of(a.length)
const e1 = await _.run(_.readerTaskSeq.chain(_.of('foo'), f), {})
assert.deepStrictEqual(e1, 3)
})
})
})

it('ask', async () => {
const e = await _.run(_.ask<number>(), 1)
return assert.deepStrictEqual(e, 1)
})

it('asks', async () => {
const e = await _.run(
_.asks((s: string) => s.length),
'foo'
)
return assert.deepStrictEqual(e, 3)
})

it('local', async () => {
const len = (s: string): number => s.length
const e = await _.run(
pipe(
_.asks((n: number) => n + 1),
_.local(len)
),
'aaa'
)
assert.deepStrictEqual(e, 4)
})

it('fromTask', async () => {
const e = await _.run(_.fromTask(task.of(1)), {})
assert.deepStrictEqual(e, 1)
})

it('fromReader', async () => {
const e = await _.fromReader(reader.of(1))({})()
assert.deepStrictEqual(e, 1)
})

it('getSemigroup', async () => {
const M = _.getSemigroup(semigroupString)
const e = await M.concat(_.of('a'), _.of('b'))({})()
assert.strictEqual(e, 'ab')
})

it('getMonoid', async () => {
const M = _.getMonoid(monoidString)
const e = await M.concat(_.of('a'), M.empty)({})()
assert.strictEqual(e, 'a')
const e2 = await M.concat(M.empty, _.of('b'))({})()
assert.strictEqual(e2, 'b')
const e3 = await M.concat(_.of('a'), _.of('b'))({})()
assert.strictEqual(e3, 'ab')
})

it('reader', async () => {
const e = await _.run(_.reader(reader.of(1)), {})
assert.deepStrictEqual(e, 1)
})

it('sequence parallel', async () => {
const log: Array<string> = []
const append = (message: string): _.ReaderTask<{}, number> => _.fromTask(() => Promise.resolve(log.push(message)))
const t1 = _.readerTask.chain(append('start 1'), () => append('end 1'))
const t2 = _.readerTask.chain(append('start 2'), () => append('end 2'))
const sequenceParallel = array.sequence(_.readerTask)
const ns = await _.run(sequenceParallel([t1, t2]), {})
assert.deepStrictEqual(ns, [3, 4])
assert.deepStrictEqual(log, ['start 1', 'start 2', 'end 1', 'end 2'])
})

it('sequence series', async () => {
const log: Array<string> = []
const append = (message: string): _.ReaderTask<{}, number> => _.fromTask(() => Promise.resolve(log.push(message)))
const t1 = _.readerTask.chain(append('start 1'), () => append('end 1'))
const t2 = _.readerTask.chain(append('start 2'), () => append('end 2'))
const sequenceSeries = array.sequence(_.readerTaskSeq)
const ns = await _.run(sequenceSeries([t1, t2]), {})
assert.deepStrictEqual(ns, [2, 4])
assert.deepStrictEqual(log, ['start 1', 'end 1', 'start 2', 'end 2'])
})

describe('MonadIO', () => {
it('fromIO', async () => {
const e = await _.run(
_.readerTask.fromIO(() => 1),
{}
)
assert.deepStrictEqual(e, 1)
})
})
})
Loading

0 comments on commit 6168985

Please sign in to comment.