Skip to content

Reader

Reader: object

Defined in: Core/Reader.ts:26

ap: <R, A>(arg) => <B>(data) => Reader<R, B>

Applies a function wrapped in a Reader to a value wrapped in a Reader. Both Readers see the same environment.

R

A

Reader<R, A>

<B>(data) => Reader<R, B>

const add = (a: number) => (b: number) => a + b;
pipe(
  Reader.resolve<Config, typeof add>(add),
  Reader.ap(Reader.asks(c => c.timeout)),
  Reader.ap(Reader.resolve(5))
)(appConfig);

ask: <R>() => Reader<R, R>

Returns the full environment as the result. The fundamental way to access the environment in a pipeline.

R

Reader<R, R>

pipe(
  Reader.ask<Config>(),
  Reader.map(config => config.baseUrl)
)(appConfig); // "https://api.example.com"

asks: <R, A>(f) => Reader<R, A>

Projects a value from the environment using a selector function. Equivalent to pipe(Reader.ask(), Reader.map(f)) but more direct.

R

A

(env) => A

Reader<R, A>

const getBaseUrl: Reader<Config, string> = Reader.asks(c => c.baseUrl);
getBaseUrl(appConfig); // "https://api.example.com"

bind: <K, R, A, B>(key, f) => (data) => Reader<R, A & { [P in string]: B }>

Evaluates a new Reader using the current accumulator and attaches the output to a new key.

K extends string

R

A

B

K

(a) => Reader<R, B>

(data) => Reader<R, A & { [P in string]: B }>

pipe(
  Reader.resolve({ a: 1 }),
  Reader.bind("b", ({ a }) => Reader.resolve(a + 1))
); // Reader({ a: 1, b: 2 })

bindTo: <K>(key) => <R, A>(data) => Reader<R, { [P in string]: A }>

Lifts a Reader value into an accumulator object.

K extends string

K

<R, A>(data) => Reader<R, { [P in string]: A }>

pipe(Reader.resolve(42), Reader.bindTo("value")); // Reader({ value: 42 })

chain: <R, A, B>(f) => (data) => Reader<R, B> = chainReader

Sequences two Readers. Both see the same environment. The output of the first is passed to f, which returns the next Reader.

R

A

B

(a) => Reader<R, B>

(data) => Reader<R, B>

const buildUrl = (path: string): Reader<Config, string> =>
  Reader.asks(c => `${c.baseUrl}${path}`);

const addAuth = (url: string): Reader<Config, string> =>
  Reader.asks(c => `${url}?key=${c.apiKey}`);

pipe(
  buildUrl("/items"),
  Reader.chain(addAuth)
)(appConfig); // "https://api.example.com/items?key=secret"

local: <R2, R>(f) => <A>(data) => Reader<R2, A>

Adapts a Reader to work with a different (typically wider) environment by transforming the environment before passing it to the Reader. This lets you compose Readers that expect different environments.

R2

R

(env) => R

<A>(data) => Reader<R2, A>

type AppEnv = { db: DbPool; config: Config; logger: Logger };

// buildUrl only needs Config
const buildUrl: Reader<Config, string> = Reader.asks(c => c.baseUrl);

// Zoom in from AppEnv to Config
const buildUrlFromApp: Reader<AppEnv, string> =
  pipe(buildUrl, Reader.local((env: AppEnv) => env.config));

buildUrlFromApp(appEnv); // works with the full AppEnv

map: <R, A, B>(f) => (data) => Reader<R, B> = mapReader

Transforms the value produced by a Reader.

R

A

B

(a) => B

(data) => Reader<R, B>

pipe(
  Reader.asks((c: Config) => c.baseUrl),
  Reader.map(url => url.toUpperCase())
)(appConfig); // "HTTPS://API.EXAMPLE.COM"

resolve: <R, A>(value) => Reader<R, A>

Lifts a pure value into a Reader. The environment is ignored.

R

A

A

Reader<R, A>

const always42: Reader<Config, number> = Reader.resolve(42);
always42(anyConfig); // 42

run: <R>(env) => <A>(data) => A

Runs a Reader by supplying the environment. Use this at the edge of your program where the environment is available.

R

R

<A>(data) => A

pipe(
  buildEndpoint("/users"),
  Reader.run(appConfig)
); // "https://api.example.com/users?key=secret"

tap: <R, A>(f) => (data) => Reader<R, A>

Executes a side effect on the produced value without changing the Reader. Useful for logging or debugging inside a pipeline.

R

A

(a) => void

(data) => Reader<R, A>

pipe(
  buildUrl("/users"),
  Reader.tap(url => console.log("Requesting:", url)),
  Reader.chain(addAuth)
)(appConfig);