I have a function that looks up a value from the environment:
type Env = unknown
declare const getFromEnv: (key: string) => Reader<Env, Option<number>>
At the same time I have an array of keys, and I want to look up the value of the last key in the environment, but this returns Option<Reader<Env, Option<number>>
type:
const getLastFromEnv = (keys: string[]): Reader<Env, Option<number>> =>
pipe(keys, array.last, option.map(getFromEnv), ...? ) // Option<Reader<Env, Option<number>>
How can I make it return Reader<Env, Option<number>>
? Thanks!
You can write this transformation explicitly with fold
from the Option
library, but it does feel a bit roundabout:
import * as R from 'fp-ts/lib/Reader';
import * as O from 'fp-ts/lib/Option';
import * as A from 'fp-ts/lib/Array';
import { pipe } from 'fp-ts/lib/function';
type Env = unknown;
declare function getFromEnv(key: string): R.Reader<Env, O.Option<number>>;
function lookUpLastKey(keys: string[]): R.Reader<Env, O.Option<number>> {
return pipe(
keys,
A.last,
O.fold(
// Handle the case that there was no last element in the array
// By explicitly returning a Reader that returns none
(): R.Reader<Env, O.Option<number>> => () => O.none,
// If there was a string, then the function you have is
// exactly what you need.
getFromEnv,
)
)
}
Another option would be to instead use a ReaderEither
which bundles together Reader
logic and Either
logic into a single type class. With ReaderEither
you can more directly fold the failure to find the last value in an array into the output type:
import * as RE from "fp-ts/lib/ReaderEither";
import * as A from "fp-ts/lib/Array";
import { constant, pipe } from "fp-ts/lib/function";
type Env = unknown;
// Instead of a single `None` value, `Either` allows for an arbitrary
// value to be stored in the error case. Here I've just chosen `null`
// because I need to put something in there on a `Left`.
declare function getFromEnv(key: string): RE.ReaderEither<Env, null, number>;
function lookUpLastKey(keys: string[]): RE.ReaderEither<Env, null, number> {
return pipe(
keys,
A.last,
// This is a helper transformation that avoids explicitly writing it
// yourself with fold. If the last value was `None` this will replace
// It with a Left value holding `null`.
RE.fromOption(constant(null)),
// Chaining will replace the old ReaderEither with the one returned
// by your helper but only if the input `ReaderEither` is a `Right`.
RE.chain(getFromEnv)
);
}