Repository: gcanti/fp-ts
Pull request #1495 (2021-04-24 16:43:41)

Add from reader chain first reader k
backport of #1493


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 326c4c90..50e8f07f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -140,15 +140,21 @@ high state of flux, you're at risk of it changing without notice.
     - add `asksEW`, `asksW`
     - add `orElseFirst` / `orElseFirstW`
     - add `orLeft`
+    - add `chainReaderKW`
+    - add `chainFirstReaderK`, `chainFirstReaderKW`
   - `ReaderTask`
     - add `asksEW`, `asksW`
+    - add `chainReaderKW`
+    - add `chainFirstReaderK`, `chainFirstReaderKW`
   - `ReaderTaskEither`
     - add `asksEW`, `asksW`
     - add `orElseFirst` / `orElseFirstW`
     - add `orLeft`
     - add `fromReaderTaskK`
-    - add `chainReaderTaskK`
-    - add `chainReaderTaskKW`
+    - add `chainReaderKW`
+    - add `chainReaderTaskK`, `chainReaderTaskKW`
+    - add `chainFirstReaderK`, `chainFirstReaderKW`
+    - add `chainFirstReaderTaskK`, `chainFirstReaderTaskKW`
   - `ReadonlyArray`
     - add `prependW`, `appendW` (@thewilkybarkid)
     - add `filterE`
@@ -216,6 +222,8 @@ high state of flux, you're at risk of it changing without notice.
     - add `chainStateK`
     - add `local`
     - add `asksEW`, `asksW`
+    - add `chainReaderKW`
+    - add `chainFirstReaderK`, `chainFirstReaderKW`
   - `string`
     - add `toUpperCase`
   - `struct`
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index 5895e42f..7d622532 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -1851,7 +1851,7 @@ export declare const matchLeftW: <B, A, C>(
 ) => (as: A[]) => B | C
 ```
 
-Added in v3.0.0
+Added in v2.11.0
 
 ## matchRight
 
diff --git a/docs/modules/FromReader.ts.md b/docs/modules/FromReader.ts.md
index a171d30e..0aeb7ae2 100644
--- a/docs/modules/FromReader.ts.md
+++ b/docs/modules/FromReader.ts.md
@@ -15,6 +15,7 @@ Added in v2.11.0
 <h2 class="text-delta">Table of contents</h2>
 
 - [combinators](#combinators)
+  - [chainFirstReaderK](#chainfirstreaderk)
   - [chainReaderK](#chainreaderk)
   - [fromReaderK](#fromreaderk)
 - [constructors](#constructors)
@@ -31,6 +32,35 @@ Added in v2.11.0
 
 # combinators
 
+## chainFirstReaderK
+
+**Signature**
+
+```ts
+export declare function chainFirstReaderK<M extends URIS4>(
+  F: FromReader4<M>,
+  M: Chain4<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => <S, E>(ma: Kind4<M, S, R, E, A>) => Kind4<M, S, R, E, A>
+export declare function chainFirstReaderK<M extends URIS3>(
+  F: FromReader3<M>,
+  M: Chain3<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => <E>(ma: Kind3<M, R, E, A>) => Kind3<M, R, E, A>
+export declare function chainFirstReaderK<M extends URIS3, E>(
+  F: FromReader3C<M, E>,
+  M: Chain3C<M, E>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: Kind3<M, R, E, A>) => Kind3<M, R, E, A>
+export declare function chainFirstReaderK<M extends URIS2>(
+  F: FromReader2<M>,
+  M: Chain2<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: Kind2<M, R, A>) => Kind2<M, R, A>
+export declare function chainFirstReaderK<M>(
+  F: FromReader<M>,
+  M: Chain<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: HKT2<M, R, A>) => HKT2<M, R, A>
+```
+
+Added in v2.11.0
+
 ## chainReaderK
 
 **Signature**
diff --git a/docs/modules/ReaderEither.ts.md b/docs/modules/ReaderEither.ts.md
index 72152fd1..86fd864e 100644
--- a/docs/modules/ReaderEither.ts.md
+++ b/docs/modules/ReaderEither.ts.md
@@ -38,9 +38,12 @@ Added in v2.0.0
   - [chainEitherK](#chaineitherk)
   - [chainEitherKW](#chaineitherkw)
   - [chainFirst](#chainfirst)
+  - [chainFirstReaderK](#chainfirstreaderk)
+  - [chainFirstReaderKW](#chainfirstreaderkw)
   - [chainFirstW](#chainfirstw)
   - [chainOptionK](#chainoptionk)
   - [chainReaderK](#chainreaderk)
+  - [chainReaderKW](#chainreaderkw)
   - [filterOrElse](#filterorelse)
   - [filterOrElseW](#filterorelsew)
   - [flap](#flap)
@@ -375,6 +378,32 @@ export declare const chainFirst: <R, E, A, B>(
 
 Added in v2.0.0
 
+## chainFirstReaderK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => R.Reader<R, B>
+) => <E = never>(ma: ReaderEither<R, E, A>) => ReaderEither<R, E, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderKW
+
+Less strict version of [`chainReaderK`](#chainReaderK).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2, E = never>(ma: ReaderEither<R2, E, A>) => ReaderEither<R1 & R2, E, A>
+```
+
+Added in v2.11.0
+
 ## chainFirstW
 
 Less strict version of [`chainFirst`](#chainfirst)
@@ -415,6 +444,20 @@ export declare const chainReaderK: <A, R, B>(
 
 Added in v2.11.0
 
+## chainReaderKW
+
+Less strict version of [`chainReaderK`](#chainReaderK).
+
+**Signature**
+
+```ts
+export declare const chainReaderKW: <A, R2, B>(
+  f: (a: A) => R.Reader<R2, B>
+) => <R1, E = never>(ma: ReaderEither<R1, E, A>) => ReaderEither<R1 & R2, E, B>
+```
+
+Added in v2.11.0
+
 ## filterOrElse
 
 **Signature**
diff --git a/docs/modules/ReaderTask.ts.md b/docs/modules/ReaderTask.ts.md
index 44918f59..1c266bc4 100644
--- a/docs/modules/ReaderTask.ts.md
+++ b/docs/modules/ReaderTask.ts.md
@@ -29,10 +29,13 @@ Added in v2.3.0
   - [asksEW](#asksew)
   - [chainFirst](#chainfirst)
   - [chainFirstIOK](#chainfirstiok)
+  - [chainFirstReaderK](#chainfirstreaderk)
+  - [chainFirstReaderKW](#chainfirstreaderkw)
   - [chainFirstTaskK](#chainfirsttaskk)
   - [chainFirstW](#chainfirstw)
   - [chainIOK](#chainiok)
   - [chainReaderK](#chainreaderk)
+  - [chainReaderKW](#chainreaderkw)
   - [chainTaskK](#chaintaskk)
   - [flap](#flap)
   - [flatten](#flatten)
@@ -249,6 +252,32 @@ export declare const chainFirstIOK: <A, B>(f: (a: A) => IO<B>) => <E>(first: Rea
 
 Added in v2.10.0
 
+## chainFirstReaderK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => R.Reader<R, B>
+) => (ma: ReaderTask<R, A>) => ReaderTask<R, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderKW
+
+Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2>(ma: ReaderTask<R2, A>) => ReaderTask<R1 & R2, A>
+```
+
+Added in v2.11.0
+
 ## chainFirstTaskK
 
 **Signature**
@@ -295,6 +324,20 @@ export declare const chainReaderK: <A, R, B>(f: (a: A) => R.Reader<R, B>) => (ma
 
 Added in v2.11.0
 
+## chainReaderKW
+
+Less strict version of [`chainReaderK`](#chainReaderK).
+
+**Signature**
+
+```ts
+export declare const chainReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2>(ma: ReaderTask<R2, A>) => ReaderTask<R1 & R2, B>
+```
+
+Added in v2.11.0
+
 ## chainTaskK
 
 **Signature**
diff --git a/docs/modules/ReaderTaskEither.ts.md b/docs/modules/ReaderTaskEither.ts.md
index bd84f090..108daaa8 100644
--- a/docs/modules/ReaderTaskEither.ts.md
+++ b/docs/modules/ReaderTaskEither.ts.md
@@ -39,6 +39,10 @@ Added in v2.0.0
   - [chainEitherKW](#chaineitherkw)
   - [chainFirst](#chainfirst)
   - [chainFirstIOK](#chainfirstiok)
+  - [chainFirstReaderK](#chainfirstreaderk)
+  - [chainFirstReaderKW](#chainfirstreaderkw)
+  - [chainFirstReaderTaskK](#chainfirstreadertaskk)
+  - [chainFirstReaderTaskKW](#chainfirstreadertaskkw)
   - [chainFirstTaskK](#chainfirsttaskk)
   - [chainFirstW](#chainfirstw)
   - [chainIOEitherK](#chainioeitherk)
@@ -46,6 +50,7 @@ Added in v2.0.0
   - [chainIOK](#chainiok)
   - [chainOptionK](#chainoptionk)
   - [chainReaderK](#chainreaderk)
+  - [chainReaderKW](#chainreaderkw)
   - [chainReaderTaskK](#chainreadertaskk)
   - [chainReaderTaskKW](#chainreadertaskkw)
   - [chainTaskEitherK](#chaintaskeitherk)
@@ -429,6 +434,58 @@ export declare const chainFirstIOK: <A, B>(
 
 Added in v2.10.0
 
+## chainFirstReaderK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => R.Reader<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderKW
+
+Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2, E = never>(ma: ReaderTaskEither<R2, E, A>) => ReaderTaskEither<R1 & R2, E, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderTaskK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderTaskK: <A, R, B>(
+  f: (a: A) => RT.ReaderTask<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderTaskKW
+
+Less strict version of [`chainFirstReaderTaskK`](#chainFirstReaderTaskK).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderTaskKW: <A, R2, B>(
+  f: (a: A) => RT.ReaderTask<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, A>
+```
+
+Added in v2.11.0
+
 ## chainFirstTaskK
 
 **Signature**
@@ -519,6 +576,20 @@ export declare const chainReaderK: <A, R, B>(
 
 Added in v2.11.0
 
+## chainReaderKW
+
+Less strict version of [`chainReaderK`](#chainReaderK).
+
+**Signature**
+
+```ts
+export declare const chainReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2, E = never>(ma: ReaderTaskEither<R2, E, A>) => ReaderTaskEither<R1 & R2, E, B>
+```
+
+Added in v2.11.0
+
 ## chainReaderTaskK
 
 **Signature**
diff --git a/docs/modules/StateReaderTaskEither.ts.md b/docs/modules/StateReaderTaskEither.ts.md
index f63e2e8a..5d7f0292 100644
--- a/docs/modules/StateReaderTaskEither.ts.md
+++ b/docs/modules/StateReaderTaskEither.ts.md
@@ -39,6 +39,8 @@ Added in v2.0.0
   - [chainEitherKW](#chaineitherkw)
   - [chainFirst](#chainfirst)
   - [chainFirstIOK](#chainfirstiok)
+  - [chainFirstReaderK](#chainfirstreaderk)
+  - [chainFirstReaderKW](#chainfirstreaderkw)
   - [chainFirstTaskK](#chainfirsttaskk)
   - [chainFirstW](#chainfirstw)
   - [chainIOEitherK](#chainioeitherk)
@@ -46,6 +48,7 @@ Added in v2.0.0
   - [chainIOK](#chainiok)
   - [chainOptionK](#chainoptionk)
   - [chainReaderK](#chainreaderk)
+  - [chainReaderKW](#chainreaderkw)
   - [chainReaderTaskEitherK](#chainreadertaskeitherk)
   - [chainReaderTaskEitherKW](#chainreadertaskeitherkw)
   - [chainStateK](#chainstatek)
@@ -414,6 +417,32 @@ export declare const chainFirstIOK: <A, B>(
 
 Added in v2.10.0
 
+## chainFirstReaderK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => R.Reader<R, B>
+) => <S, E = never>(ma: StateReaderTaskEither<S, R, E, A>) => StateReaderTaskEither<S, R, E, A>
+```
+
+Added in v2.11.0
+
+## chainFirstReaderKW
+
+Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <S, R2, E = never>(ma: StateReaderTaskEither<S, R2, E, A>) => StateReaderTaskEither<S, R2, E, A>
+```
+
+Added in v2.11.0
+
 ## chainFirstTaskK
 
 **Signature**
@@ -506,6 +535,20 @@ export declare const chainReaderK: <A, R, B>(
 
 Added in v2.11.0
 
+## chainReaderKW
+
+Less strict version of [`chainReaderK`](#chainReaderK).
+
+**Signature**
+
+```ts
+export declare const chainReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <S, R2, E = never>(ma: StateReaderTaskEither<S, R2, E, A>) => StateReaderTaskEither<S, R1 & R2, E, B>
+```
+
+Added in v2.11.0
+
 ## chainReaderTaskEitherK
 
 **Signature**
diff --git a/src/Array.ts b/src/Array.ts
index 855cacc6..a3784b36 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -201,7 +201,7 @@ export const match: <B, A>(onEmpty: Lazy<B>, onNonEmpty: (as: NonEmptyArray<A>)
  * Less strict version of [`matchLeft`](#matchLeft).
  *
  * @category destructors
- * @since 3.0.0
+ * @since 2.11.0
  */
 export const matchLeftW = <B, A, C>(onEmpty: Lazy<B>, onNonEmpty: (head: A, tail: Array<A>) => C) => (
   as: Array<A>
diff --git a/src/FromReader.ts b/src/FromReader.ts
index cb4d1434..f0476c14 100644
--- a/src/FromReader.ts
+++ b/src/FromReader.ts
@@ -3,7 +3,7 @@
  *
  * @since 2.11.0
  */
-import { Chain, Chain2, Chain3, Chain3C, Chain4 } from './Chain'
+import { Chain, Chain2, Chain3, Chain3C, Chain4, chainFirst } from './Chain'
 import { flow } from './function'
 import { HKT2, Kind2, Kind3, Kind4, URIS2, URIS3, URIS4 } from './HKT'
 import * as R from './Reader'
@@ -150,3 +150,34 @@ export function chainReaderK<M extends URIS2>(
   const fromReaderKF = fromReaderK(F)
   return (f) => (ma) => M.chain(ma, fromReaderKF(f))
 }
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export function chainFirstReaderK<M extends URIS4>(
+  F: FromReader4<M>,
+  M: Chain4<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => <S, E>(ma: Kind4<M, S, R, E, A>) => Kind4<M, S, R, E, A>
+export function chainFirstReaderK<M extends URIS3>(
+  F: FromReader3<M>,
+  M: Chain3<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => <E>(ma: Kind3<M, R, E, A>) => Kind3<M, R, E, A>
+export function chainFirstReaderK<M extends URIS3, E>(
+  F: FromReader3C<M, E>,
+  M: Chain3C<M, E>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: Kind3<M, R, E, A>) => Kind3<M, R, E, A>
+export function chainFirstReaderK<M extends URIS2>(
+  F: FromReader2<M>,
+  M: Chain2<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: Kind2<M, R, A>) => Kind2<M, R, A>
+export function chainFirstReaderK<M>(
+  F: FromReader<M>,
+  M: Chain<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: HKT2<M, R, A>) => HKT2<M, R, A>
+export function chainFirstReaderK<M extends URIS2>(
+  F: FromReader2<M>,
+  M: Chain2<M>
+): <A, R, B>(f: (a: A) => Reader<R, B>) => (ma: Kind2<M, R, A>) => Kind2<M, R, A> {
+  return flow(fromReaderK(F), chainFirst(M))
+}
diff --git a/src/ReaderEither.ts b/src/ReaderEither.ts
index e1a9020e..59a1e721 100644
--- a/src/ReaderEither.ts
+++ b/src/ReaderEither.ts
@@ -37,6 +37,7 @@ import {
   ask as ask_,
   asks as asks_,
   chainReaderK as chainReaderK_,
+  chainFirstReaderK as chainFirstReaderK_,
   FromReader3,
   fromReaderK as fromReaderK_
 } from './FromReader'
@@ -718,6 +719,36 @@ export const chainReaderK: <A, R, B>(
   /*#__PURE__*/
   chainReaderK_(FromReader, Chain)
 
+/**
+ * Less strict version of [`chainReaderK`](#chainReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainReaderKW: <A, R2, B>(
+  f: (a: A) => Reader<R2, B>
+) => <R1, E = never>(ma: ReaderEither<R1, E, A>) => ReaderEither<R1 & R2, E, B> = chainReaderK as any
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => Reader<R, B>
+) => <E = never>(ma: ReaderEither<R, E, A>) => ReaderEither<R, E, A> =
+  /*#__PURE__*/
+  chainFirstReaderK_(FromReader, Chain)
+
+/**
+ * Less strict version of [`chainReaderK`](#chainReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => Reader<R1, B>
+) => <R2, E = never>(ma: ReaderEither<R2, E, A>) => ReaderEither<R1 & R2, E, A> = chainFirstReaderK as any
+
 /**
  * @category instances
  * @since 2.7.0
diff --git a/src/ReaderTask.ts b/src/ReaderTask.ts
index d7d12a64..8d0ca046 100644
--- a/src/ReaderTask.ts
+++ b/src/ReaderTask.ts
@@ -15,6 +15,7 @@ import {
   ask as ask_,
   asks as asks_,
   chainReaderK as chainReaderK_,
+  chainFirstReaderK as chainFirstReaderK_,
   FromReader2,
   fromReaderK as fromReaderK_
 } from './FromReader'
@@ -460,6 +461,34 @@ export const chainReaderK =
   /*#__PURE__*/
   chainReaderK_(FromReader, Chain)
 
+/**
+ * Less strict version of [`chainReaderK`](#chainReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2>(ma: ReaderTask<R2, A>) => ReaderTask<R1 & R2, B> = chainReaderK as any
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderK =
+  /*#__PURE__*/
+  chainFirstReaderK_(FromReader, Chain)
+
+/**
+ * Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2>(ma: ReaderTask<R2, A>) => ReaderTask<R1 & R2, A> = chainFirstReaderK as any
+
 /**
  * @category instances
  * @since 2.10.0
diff --git a/src/ReaderTaskEither.ts b/src/ReaderTaskEither.ts
index c40e404a..7a544859 100644
--- a/src/ReaderTaskEither.ts
+++ b/src/ReaderTaskEither.ts
@@ -39,6 +39,7 @@ import {
   ask as ask_,
   asks as asks_,
   chainReaderK as chainReaderK_,
+  chainFirstReaderK as chainFirstReaderK_,
   FromReader3,
   fromReaderK as fromReaderK_
 } from './FromReader'
@@ -942,6 +943,36 @@ export const chainReaderK: <A, R, B>(
   /*#__PURE__*/
   chainReaderK_(FromReader, Chain)
 
+/**
+ * Less strict version of [`chainReaderK`](#chainReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2, E = never>(ma: ReaderTaskEither<R2, E, A>) => ReaderTaskEither<R1 & R2, E, B> = chainReaderK as any
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => R.Reader<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A> =
+  /*#__PURE__*/
+  chainFirstReaderK_(FromReader, Chain)
+
+/**
+ * Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => R.Reader<R1, B>
+) => <R2, E = never>(ma: ReaderTaskEither<R2, E, A>) => ReaderTaskEither<R1 & R2, E, A> = chainFirstReaderK as any
+
 /**
  * @category combinators
  * @since 2.11.0
@@ -969,6 +1000,25 @@ export const chainReaderTaskK: <A, R, B>(
   f: (a: A) => RT.ReaderTask<R, B>
 ) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, B> = chainReaderTaskKW
 
+/**
+ * Less strict version of [`chainFirstReaderTaskK`](#chainFirstReaderTaskK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderTaskKW: <A, R2, B>(
+  f: (a: A) => RT.ReaderTask<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, A> = (f) =>
+  chainFirstW(fromReaderTaskK(f))
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderTaskK: <A, R, B>(
+  f: (a: A) => RT.ReaderTask<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A> = chainFirstReaderTaskKW
+
 /**
  * @category instances
  * @since 2.10.0
diff --git a/src/StateReaderTaskEither.ts b/src/StateReaderTaskEither.ts
index 3b0390f3..2b58be5d 100644
--- a/src/StateReaderTaskEither.ts
+++ b/src/StateReaderTaskEither.ts
@@ -23,6 +23,7 @@ import {
   ask as ask_,
   asks as asks_,
   chainReaderK as chainReaderK_,
+  chainFirstReaderK as chainFirstReaderK_,
   FromReader4,
   fromReaderK as fromReaderK_
 } from './FromReader'
@@ -833,6 +834,40 @@ export const chainReaderK: <A, R, B>(
   /*#__PURE__*/
   chainReaderK_(FromReader, Chain)
 
+/**
+ * Less strict version of [`chainReaderK`](#chainReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainReaderKW: <A, R1, B>(
+  f: (a: A) => Reader<R1, B>
+) => <S, R2, E = never>(
+  ma: StateReaderTaskEither<S, R2, E, A>
+) => StateReaderTaskEither<S, R1 & R2, E, B> = chainReaderK as any
+
+/**
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderK: <A, R, B>(
+  f: (a: A) => Reader<R, B>
+) => <S, E = never>(ma: StateReaderTaskEither<S, R, E, A>) => StateReaderTaskEither<S, R, E, A> =
+  /*#__PURE__*/
+  chainFirstReaderK_(FromReader, Chain)
+
+/**
+ * Less strict version of [`chainFirstReaderK`](#chainFirstReaderK).
+ *
+ * @category combinators
+ * @since 2.11.0
+ */
+export const chainFirstReaderKW: <A, R1, B>(
+  f: (a: A) => Reader<R1, B>
+) => <S, R2, E = never>(
+  ma: StateReaderTaskEither<S, R2, E, A>
+) => StateReaderTaskEither<S, R2, E, A> = chainFirstReaderK as any
+
 /**
  * @category instances
  * @since 2.10.0


Test patch:
diff --git a/test/ReaderEither.ts b/test/ReaderEither.ts
index bc5660b1..8e1311f9 100644
--- a/test/ReaderEither.ts
+++ b/test/ReaderEither.ts
@@ -304,4 +304,20 @@ describe('ReaderEither', () => {
     U.deepStrictEqual(pipe(_.right(3), f)(2), E.right(6))
     U.deepStrictEqual(pipe(_.left('a'), f)(2), E.left('a'))
   })
+
+  it('chainReaderKW', () => {
+    const f = _.chainReaderKW((): R.Reader<unknown, number> => () => 2)
+    U.deepStrictEqual(pipe(_.right<{}, never, number>(3), f)({}), E.right(2))
+  })
+
+  it('chainFirstReaderK', () => {
+    const f = _.chainFirstReaderK((n: number): R.Reader<number, number> => (c) => n * c)
+    U.deepStrictEqual(pipe(_.right(3), f)(2), E.right(3))
+    U.deepStrictEqual(pipe(_.left('a'), f)(2), E.left('a'))
+  })
+
+  it('chainFirstReaderKW', () => {
+    const f = _.chainFirstReaderKW((): R.Reader<unknown, number> => () => 2)
+    U.deepStrictEqual(pipe(_.right<{}, never, number>(3), f)({}), E.right(3))
+  })
 })
diff --git a/test/ReaderTaskEither.ts b/test/ReaderTaskEither.ts
index 0f0d6363..2aa88404 100644
--- a/test/ReaderTaskEither.ts
+++ b/test/ReaderTaskEither.ts
@@ -423,6 +423,11 @@ describe('ReaderTaskEither', () => {
     U.deepStrictEqual(await pipe(_.right<{}, never, string>('a'), _.chainReaderTaskKW(f))({})(), E.right(1))
   })
 
+  it('chainFirstReaderTaskKW', async () => {
+    const f = flow(S.size, RT.of)
+    U.deepStrictEqual(await pipe(_.right<{}, never, string>('a'), _.chainFirstReaderTaskKW(f))({})(), E.right('a'))
+  })
+
   // -------------------------------------------------------------------------------------
   // utils
   // -------------------------------------------------------------------------------------