Repository: gcanti/fp-ts
Pull request #1774 (2022-09-15 09:44:54)

Add ReaderIO constructors/combinators to ReaderTaskEither
Copied from https://github.com/gcanti/fp-ts-contrib/pull/90.


Patch:
diff --git a/README.md b/README.md
index 3216c14c..03e2b04e 100644
--- a/README.md
+++ b/README.md
@@ -69,7 +69,7 @@ Make sure to always have a single version of `fp-ts` installed in your project.
 If you need help with `fp-ts` check out:
 
 - this [Discord server](https://discord.gg/HVWmBBXM8A)
-- the `#fp-ts` channel on [FP slack](https://fpchat-invite.herokuapp.com).
+- the `#fp-ts` channel on [FP slack](https://fpslack.com/).
 
 # Development
 
diff --git a/docs/modules/ReaderTask.ts.md b/docs/modules/ReaderTask.ts.md
index 580cb8d2..a379c485 100644
--- a/docs/modules/ReaderTask.ts.md
+++ b/docs/modules/ReaderTask.ts.md
@@ -29,11 +29,15 @@ Added in v2.3.0
   - [asksReaderTaskW](#asksreadertaskw)
   - [chainFirst](#chainfirst)
   - [chainFirstIOK](#chainfirstiok)
+  - [chainFirstReaderIOK](#chainfirstreaderiok)
+  - [chainFirstReaderIOKW](#chainfirstreaderiokw)
   - [chainFirstReaderK](#chainfirstreaderk)
   - [chainFirstReaderKW](#chainfirstreaderkw)
   - [chainFirstTaskK](#chainfirsttaskk)
   - [chainFirstW](#chainfirstw)
   - [chainIOK](#chainiok)
+  - [chainReaderIOK](#chainreaderiok)
+  - [chainReaderIOKW](#chainreaderiokw)
   - [chainReaderK](#chainreaderk)
   - [chainReaderKW](#chainreaderkw)
   - [chainTaskK](#chaintaskk)
@@ -41,6 +45,7 @@ Added in v2.3.0
   - [flatten](#flatten)
   - [flattenW](#flattenw)
   - [fromIOK](#fromiok)
+  - [fromReaderIOK](#fromreaderiok)
   - [fromReaderK](#fromreaderk)
   - [fromTaskK](#fromtaskk)
   - [local](#local)
@@ -72,6 +77,7 @@ Added in v2.3.0
 - [natural transformations](#natural-transformations)
   - [fromIO](#fromio)
   - [fromReader](#fromreader)
+  - [fromReaderIO](#fromreaderio)
   - [fromTask](#fromtask)
 - [utils](#utils)
   - [ApT](#apt)
@@ -266,6 +272,32 @@ export declare const chainFirstIOK: <A, B>(f: (a: A) => IO<B>) => <E>(first: Rea
 
 Added in v2.10.0
 
+## chainFirstReaderIOK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderIOK: <A, R, B>(
+  f: (a: A) => RIO.ReaderIO<R, B>
+) => (ma: ReaderTask<R, A>) => ReaderTask<R, A>
+```
+
+Added in v2.13.0
+
+## chainFirstReaderIOKW
+
+Less strict version of [`chainFirstReaderIOK`](#chainfirstreaderiok).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderIOKW: <A, R2, B>(
+  f: (a: A) => RIO.ReaderIO<R2, B>
+) => <R1>(ma: ReaderTask<R1, A>) => ReaderTask<R1 & R2, A>
+```
+
+Added in v2.13.0
+
 ## chainFirstReaderK
 
 **Signature**
@@ -332,6 +364,32 @@ export declare const chainIOK: <A, B>(f: (a: A) => IO<B>) => <E>(first: ReaderTa
 
 Added in v2.4.0
 
+## chainReaderIOK
+
+**Signature**
+
+```ts
+export declare const chainReaderIOK: <A, R, B>(
+  f: (a: A) => RIO.ReaderIO<R, B>
+) => (ma: ReaderTask<R, A>) => ReaderTask<R, B>
+```
+
+Added in v2.13.0
+
+## chainReaderIOKW
+
+Less strict version of [`chainReaderIOK`](#chainreaderiok).
+
+**Signature**
+
+```ts
+export declare const chainReaderIOKW: <A, R2, B>(
+  f: (a: A) => RIO.ReaderIO<R2, B>
+) => <R1>(ma: ReaderTask<R1, A>) => ReaderTask<R1 & R2, B>
+```
+
+Added in v2.13.0
+
 ## chainReaderK
 
 **Signature**
@@ -416,6 +474,18 @@ export declare const fromIOK: <A, B>(f: (...a: A) => IO<B>) => <E>(...a: A) => R
 
 Added in v2.4.0
 
+## fromReaderIOK
+
+**Signature**
+
+```ts
+export declare const fromReaderIOK: <A extends readonly unknown[], R, B>(
+  f: (...a: A) => RIO.ReaderIO<R, B>
+) => (...a: A) => ReaderTask<R, B>
+```
+
+Added in v2.13.0
+
 ## fromReaderK
 
 **Signature**
@@ -723,6 +793,16 @@ export declare const fromReader: NaturalTransformation22<'Reader', 'ReaderTask'>
 
 Added in v2.3.0
 
+## fromReaderIO
+
+**Signature**
+
+```ts
+export declare const fromReaderIO: <R, A>(fa: RIO.ReaderIO<R, A>) => ReaderTask<R, A>
+```
+
+Added in v2.13.0
+
 ## fromTask
 
 **Signature**
diff --git a/docs/modules/ReaderTaskEither.ts.md b/docs/modules/ReaderTaskEither.ts.md
index 6ce370c2..6ce6a059 100644
--- a/docs/modules/ReaderTaskEither.ts.md
+++ b/docs/modules/ReaderTaskEither.ts.md
@@ -45,6 +45,8 @@ Added in v2.0.0
   - [chainFirstIOK](#chainfirstiok)
   - [chainFirstReaderEitherK](#chainfirstreadereitherk)
   - [chainFirstReaderEitherKW](#chainfirstreadereitherkw)
+  - [chainFirstReaderIOK](#chainfirstreaderiok)
+  - [chainFirstReaderIOKW](#chainfirstreaderiokw)
   - [chainFirstReaderK](#chainfirstreaderk)
   - [chainFirstReaderKW](#chainfirstreaderkw)
   - [chainFirstReaderTaskK](#chainfirstreadertaskk)
@@ -59,6 +61,8 @@ Added in v2.0.0
   - [chainOptionK](#chainoptionk)
   - [chainReaderEitherK](#chainreadereitherk)
   - [chainReaderEitherKW](#chainreadereitherkw)
+  - [chainReaderIOK](#chainreaderiok)
+  - [chainReaderIOKW](#chainreaderiokw)
   - [chainReaderK](#chainreaderk)
   - [chainReaderKW](#chainreaderkw)
   - [chainReaderTaskK](#chainreadertaskk)
@@ -76,6 +80,7 @@ Added in v2.0.0
   - [fromIOK](#fromiok)
   - [fromOptionK](#fromoptionk)
   - [fromReaderEitherK](#fromreadereitherk)
+  - [fromReaderIOK](#fromreaderiok)
   - [fromReaderK](#fromreaderk)
   - [fromReaderTaskK](#fromreadertaskk)
   - [fromTaskEitherK](#fromtaskeitherk)
@@ -95,11 +100,13 @@ Added in v2.0.0
   - [left](#left)
   - [leftIO](#leftio)
   - [leftReader](#leftreader)
+  - [leftReaderIO](#leftreaderio)
   - [leftReaderTask](#leftreadertask)
   - [leftTask](#lefttask)
   - [right](#right)
   - [rightIO](#rightio)
   - [rightReader](#rightreader)
+  - [rightReaderIO](#rightreaderio)
   - [rightReaderTask](#rightreadertask)
   - [rightTask](#righttask)
 - [destructors](#destructors)
@@ -557,6 +564,32 @@ export declare const chainFirstReaderEitherKW: <R2, E2, A, B>(
 
 Added in v2.11.0
 
+## chainFirstReaderIOK
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderIOK: <A, R, B>(
+  f: (a: A) => RIO.ReaderIO<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A>
+```
+
+Added in v2.13.0
+
+## chainFirstReaderIOKW
+
+Less strict version of [`chainFirstReaderIOK`](#chainfirstreaderiok).
+
+**Signature**
+
+```ts
+export declare const chainFirstReaderIOKW: <A, R2, B>(
+  f: (a: A) => RIO.ReaderIO<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, A>
+```
+
+Added in v2.13.0
+
 ## chainFirstReaderK
 
 **Signature**
@@ -751,6 +784,32 @@ export declare const chainReaderEitherKW: <R2, E2, A, B>(
 
 Added in v2.11.0
 
+## chainReaderIOK
+
+**Signature**
+
+```ts
+export declare const chainReaderIOK: <A, R, B>(
+  f: (a: A) => RIO.ReaderIO<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, B>
+```
+
+Added in v2.13.0
+
+## chainReaderIOKW
+
+Less strict version of [`chainReaderIOK`](#chainreaderiok).
+
+**Signature**
+
+```ts
+export declare const chainReaderIOKW: <A, R2, B>(
+  f: (a: A) => RIO.ReaderIO<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, B>
+```
+
+Added in v2.13.0
+
 ## chainReaderK
 
 **Signature**
@@ -989,6 +1048,18 @@ export declare const fromReaderEitherK: <R, E, A extends readonly unknown[], B>(
 
 Added in v2.11.0
 
+## fromReaderIOK
+
+**Signature**
+
+```ts
+export declare const fromReaderIOK: <A extends readonly unknown[], R, B>(
+  f: (...a: A) => RIO.ReaderIO<R, B>
+) => <E = never>(...a: A) => ReaderTaskEither<R, E, B>
+```
+
+Added in v2.13.0
+
 ## fromReaderK
 
 **Signature**
@@ -1206,6 +1277,16 @@ export declare const leftReader: <R, E = never, A = never>(me: R.Reader<R, E>) =
 
 Added in v2.0.0
 
+## leftReaderIO
+
+**Signature**
+
+```ts
+export declare const leftReaderIO: <R, E = never, A = never>(me: RIO.ReaderIO<R, E>) => ReaderTaskEither<R, E, A>
+```
+
+Added in v2.13.0
+
 ## leftReaderTask
 
 **Signature**
@@ -1256,6 +1337,16 @@ export declare const rightReader: <R, E = never, A = never>(ma: R.Reader<R, A>)
 
 Added in v2.0.0
 
+## rightReaderIO
+
+**Signature**
+
+```ts
+export declare const rightReaderIO: <R, E = never, A = never>(ma: RIO.ReaderIO<R, A>) => ReaderTaskEither<R, E, A>
+```
+
+Added in v2.13.0
+
 ## rightReaderTask
 
 **Signature**
diff --git a/dtslint/ts3.5/ReaderTask.ts b/dtslint/ts3.5/ReaderTask.ts
index ce12aa9d..20fb84af 100644
--- a/dtslint/ts3.5/ReaderTask.ts
+++ b/dtslint/ts3.5/ReaderTask.ts
@@ -1,6 +1,79 @@
 import * as _ from '../../src/ReaderTask'
+import * as RIO from '../../src/ReaderIO'
 import { pipe } from '../../src/function'
 
+interface R1 {
+  foo: string
+}
+
+interface R2 {
+  bar: string
+}
+
+//
+// fromReaderIO
+//
+
+// $ExpectType ReaderTask<R1, boolean>
+_.fromReaderIO(RIO.of<R1, boolean>(true))
+
+//
+// fromReaderIOK
+//
+
+// $ExpectType (a: boolean) => ReaderTask<R1, boolean>
+_.fromReaderIOK((a: boolean) => RIO.of<R1, boolean>(a))
+
+//
+// chainReaderIOKW
+//
+
+// $ExpectType ReaderTask<R1 & R2, boolean>
+pipe(
+  _.of<R1, number>(1),
+  _.chainReaderIOKW(() => RIO.of<R2, boolean>(true))
+)
+
+//
+// chainReaderIOK
+//
+
+// $ExpectType ReaderTask<R1, number>
+pipe(
+  _.of<R1, number>(1),
+  _.chainReaderIOK(() => RIO.of(1))
+)
+
+pipe(
+  _.of<R1, number>(1), // $ExpectError
+  _.chainReaderIOK(() => RIO.of<R2, boolean>(true))
+)
+
+//
+// chainFirstReaderIOKW
+//
+
+// $ExpectType ReaderTask<R1 & R2, number>
+pipe(
+  _.of<R1, number>(1),
+  _.chainFirstReaderIOKW(() => RIO.of<R2, boolean>(true))
+)
+
+//
+// chainFirstReaderIOK
+//
+
+// $ExpectType ReaderTask<R1, number>
+pipe(
+  _.of<R1, number>(1),
+  _.chainFirstReaderIOK(() => RIO.of(true))
+)
+
+pipe(
+  _.of<R1, number>(1), // $ExpectError
+  _.chainFirstReaderIOK(() => RIO.of<R2, boolean>(true))
+)
+
 //
 // Do
 //
diff --git a/dtslint/ts3.5/ReaderTaskEither.ts b/dtslint/ts3.5/ReaderTaskEither.ts
index a95b2257..b42b988e 100644
--- a/dtslint/ts3.5/ReaderTaskEither.ts
+++ b/dtslint/ts3.5/ReaderTaskEither.ts
@@ -1,10 +1,25 @@
 import * as _ from '../../src/ReaderTaskEither'
+import * as RIO from '../../src/ReaderIO'
 import * as RT from '../../src/ReaderTask'
 import * as E from '../../src/Either'
 import * as TE from '../../src/TaskEither'
 import * as IOE from '../../src/IOEither'
 import { pipe } from '../../src/function'
 
+//
+// rightReaderIO
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, never, boolean>
+_.rightReaderIO(RIO.of<{ a: string }, boolean>(true))
+
+//
+// leftReaderIO
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, boolean, never>
+_.leftReaderIO(RIO.of<{ a: string }, boolean>(true))
+
 //
 // getOrElseW
 //
@@ -105,6 +120,134 @@ pipe(
   _.chainIOEitherKW(() => IOE.right<number, number>(1))
 )
 
+//
+// fromReaderIOK
+//
+
+// $ExpectType <E = never>(a: boolean) => ReaderTaskEither<{ a: string; }, E, boolean>
+_.fromReaderIOK((a: boolean) => RIO.of<{ a: string }, boolean>(a))
+
+//
+// chainReaderIOKW
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; } & { b: number; }, string, boolean>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOKW(() => RIO.of<{ b: number }, boolean>(true))
+)
+
+//
+// chainReaderIOK
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOK(() => RIO.of(1))
+)
+
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOK(() => RIO.of<{ b: number }, boolean>(true)) // $ExpectError
+)
+
+//
+// chainFirstReaderIOKW
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; } & { b: number; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOKW(() => RIO.of<{ b: number }, boolean>(true))
+)
+
+//
+// chainFirstReaderIOK
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOK(() => RIO.of(true))
+)
+
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOK(() => RIO.of<{ b: number }, boolean>(true)) // $ExpectError
+)
+
+//
+// rightReaderIO
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, never, boolean>
+_.rightReaderIO(RIO.of<{ a: string }, boolean>(true))
+
+//
+// leftReaderIO
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, boolean, never>
+_.leftReaderIO(RIO.of<{ a: string }, boolean>(true))
+
+//
+// fromReaderIOK
+//
+
+// $ExpectType <E = never>(a: boolean) => ReaderTaskEither<{ a: string; }, E, boolean>
+_.fromReaderIOK((a: boolean) => RIO.of<{ a: string }, boolean>(a))
+
+//
+// chainReaderIOKW
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; } & { b: number; }, string, boolean>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOKW(() => RIO.of<{ b: number }, boolean>(true))
+)
+
+//
+// chainReaderIOK
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOK(() => RIO.of(1))
+)
+
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainReaderIOK(() => RIO.of<{ b: number }, boolean>(true)) // $ExpectError
+)
+
+//
+// chainFirstReaderIOKW
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; } & { b: number; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOKW(() => RIO.of<{ b: number }, boolean>(true))
+)
+
+//
+// chainFirstReaderIOK
+//
+
+// $ExpectType ReaderTaskEither<{ a: string; }, string, number>
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOK(() => RIO.of(true))
+)
+
+pipe(
+  _.right<{ a: string }, string, number>(1),
+  _.chainFirstReaderIOK(() => RIO.of<{ b: number }, boolean>(true)) // $ExpectError
+)
+
 //
 // do notation
 //
diff --git a/src/ReaderTask.ts b/src/ReaderTask.ts
index 2e739f9b..8f96f40f 100644
--- a/src/ReaderTask.ts
+++ b/src/ReaderTask.ts
@@ -34,6 +34,7 @@ import { MonadTask2 } from './MonadTask'
 import { Monoid } from './Monoid'
 import { Pointed2 } from './Pointed'
 import * as R from './Reader'
+import * as RIO from './ReaderIO'
 import * as RT from './ReaderT'
 import { ReadonlyNonEmptyArray } from './ReadonlyNonEmptyArray'
 import { Semigroup } from './Semigroup'
@@ -43,6 +44,7 @@ import * as T from './Task'
 // model
 // -------------------------------------------------------------------------------------
 
+import ReaderIO = RIO.ReaderIO
 import Task = T.Task
 
 /**
@@ -75,6 +77,12 @@ export const fromTask: FromTask2<URI>['fromTask'] = /*#__PURE__*/ R.of
  */
 export const fromIO: FromIO2<URI>['fromIO'] = /*#__PURE__*/ flow(T.fromIO, fromTask)
 
+/**
+ * @category natural transformations
+ * @since 2.13.0
+ */
+export const fromReaderIO: <R, A>(fa: ReaderIO<R, A>) => ReaderTask<R, A> = R.map(T.fromIO)
+
 // -------------------------------------------------------------------------------------
 // combinators
 // -------------------------------------------------------------------------------------
@@ -487,6 +495,50 @@ 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 combinators
+ * @since 2.13.0
+ */
+export const fromReaderIOK = <A extends ReadonlyArray<unknown>, R, B>(
+  f: (...a: A) => ReaderIO<R, B>
+): ((...a: A) => ReaderTask<R, B>) => (...a) => fromReaderIO(f(...a))
+
+/**
+ * Less strict version of [`chainReaderIOK`](#chainreaderiok).
+ *
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainReaderIOKW: <A, R2, B>(
+  f: (a: A) => ReaderIO<R2, B>
+) => <R1>(ma: ReaderTask<R1, A>) => ReaderTask<R1 & R2, B> = (f) => chainW(fromReaderIOK(f))
+
+/**
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainReaderIOK: <A, R, B>(
+  f: (a: A) => ReaderIO<R, B>
+) => (ma: ReaderTask<R, A>) => ReaderTask<R, B> = chainReaderIOKW
+
+/**
+ * Less strict version of [`chainFirstReaderIOK`](#chainfirstreaderiok).
+ *
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainFirstReaderIOKW: <A, R2, B>(
+  f: (a: A) => ReaderIO<R2, B>
+) => <R1>(ma: ReaderTask<R1, A>) => ReaderTask<R1 & R2, A> = (f) => chainFirstW(fromReaderIOK(f))
+
+/**
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainFirstReaderIOK: <A, R, B>(
+  f: (a: A) => ReaderIO<R, B>
+) => (ma: ReaderTask<R, A>) => ReaderTask<R, A> = chainFirstReaderIOKW
+
 /**
  * @category instances
  * @since 2.10.0
diff --git a/src/ReaderTaskEither.ts b/src/ReaderTaskEither.ts
index 1e0e8f45..923cfdbf 100644
--- a/src/ReaderTaskEither.ts
+++ b/src/ReaderTaskEither.ts
@@ -66,6 +66,7 @@ import { Pointed3 } from './Pointed'
 import { Predicate } from './Predicate'
 import * as R from './Reader'
 import { ReaderEither, URI as REURI } from './ReaderEither'
+import * as RIO from './ReaderIO'
 import * as RT from './ReaderTask'
 import { ReadonlyNonEmptyArray } from './ReadonlyNonEmptyArray'
 import { Refinement } from './Refinement'
@@ -77,6 +78,7 @@ import Either = E.Either
 import Task = T.Task
 import TaskEither = TE.TaskEither
 import Reader = R.Reader
+import ReaderIO = RIO.ReaderIO
 import ReaderTask = RT.ReaderTask
 
 // -------------------------------------------------------------------------------------
@@ -179,6 +181,22 @@ export const leftIO: <R, E = never, A = never>(me: IO<E>) => ReaderTaskEither<R,
   fromTaskEither
 )
 
+/**
+ * @category constructors
+ * @since 2.13.0
+ */
+export const rightReaderIO: <R, E = never, A = never>(ma: ReaderIO<R, A>) => ReaderTaskEither<R, E, A> = /*#__PURE__*/ (
+  ma
+) => flow(ma, TE.rightIO)
+
+/**
+ * @category constructors
+ * @since 2.13.0
+ */
+export const leftReaderIO: <R, E = never, A = never>(me: ReaderIO<R, E>) => ReaderTaskEither<R, E, A> = /*#__PURE__*/ (
+  me
+) => flow(me, TE.leftIO)
+
 // -------------------------------------------------------------------------------------
 // natural transformations
 // -------------------------------------------------------------------------------------
@@ -1180,6 +1198,52 @@ 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 combinators
+ * @since 2.13.0
+ */
+export const fromReaderIOK = <A extends ReadonlyArray<unknown>, R, B>(
+  f: (...a: A) => ReaderIO<R, B>
+): (<E = never>(...a: A) => ReaderTaskEither<R, E, B>) => (...a) => rightReaderIO(f(...a))
+
+/**
+ * Less strict version of [`chainReaderIOK`](#chainreaderiok).
+ *
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainReaderIOKW: <A, R2, B>(
+  f: (a: A) => ReaderIO<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, B> = (f) =>
+  chainW(fromReaderIOK(f))
+
+/**
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainReaderIOK: <A, R, B>(
+  f: (a: A) => ReaderIO<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, B> = chainReaderIOKW
+
+/**
+ * Less strict version of [`chainFirstReaderIOK`](#chainfirstreaderiok).
+ *
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainFirstReaderIOKW: <A, R2, B>(
+  f: (a: A) => ReaderIO<R2, B>
+) => <R1, E = never>(ma: ReaderTaskEither<R1, E, A>) => ReaderTaskEither<R1 & R2, E, A> = (f) =>
+  chainFirstW(fromReaderIOK(f))
+
+/**
+ * @category combinators
+ * @since 2.13.0
+ */
+export const chainFirstReaderIOK: <A, R, B>(
+  f: (a: A) => ReaderIO<R, B>
+) => <E = never>(ma: ReaderTaskEither<R, E, A>) => ReaderTaskEither<R, E, A> = chainFirstReaderIOKW
+
 /**
  * @category instances
  * @since 2.10.0


Test patch:
diff --git a/test/ReaderTask.ts b/test/ReaderTask.ts
index 21dfd499..952007ee 100644
--- a/test/ReaderTask.ts
+++ b/test/ReaderTask.ts
@@ -2,6 +2,7 @@ import { pipe, SK } from '../src/function'
 import * as I from '../src/IO'
 import { monoidString } from '../src/Monoid'
 import * as R from '../src/Reader'
+import * as RIO from '../src/ReaderIO'
 import * as _ from '../src/ReaderTask'
 import * as RA from '../src/ReadonlyArray'
 import { ReadonlyNonEmptyArray } from '../src/ReadonlyNonEmptyArray'
@@ -86,6 +87,10 @@ describe('ReaderTask', () => {
     U.deepStrictEqual(await _.fromReader(R.of(1))({})(), 1)
   })
 
+  it('fromReaderIO', async () => {
+    U.deepStrictEqual(await _.fromReaderIO(RIO.of(1))({})(), 1)
+  })
+
   // -------------------------------------------------------------------------------------
   // combinators
   // -------------------------------------------------------------------------------------
@@ -125,6 +130,31 @@ describe('ReaderTask', () => {
     U.deepStrictEqual(await pipe(_.of('a'), _.chain(f))({})(), 1)
   })
 
+  it('fromReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await _.fromReaderIOK(f)('a')(undefined)(), 1)
+  })
+
+  it('chainReaderIOKW', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.of('a'), _.chainReaderIOKW(f))({})(), 1)
+  })
+
+  it('chainReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.of('a'), _.chainReaderIOK(f))(undefined)(), 1)
+  })
+
+  it('chainFirstReaderIOKW', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.of('a'), _.chainFirstReaderIOKW(f))({})(), 'a')
+  })
+
+  it('chainFirstReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.of('a'), _.chainFirstReaderIOK(f))({})(), 'a')
+  })
+
   // -------------------------------------------------------------------------------------
   // instances
   // -------------------------------------------------------------------------------------
diff --git a/test/ReaderTaskEither.ts b/test/ReaderTaskEither.ts
index a7658053..9e990714 100644
--- a/test/ReaderTaskEither.ts
+++ b/test/ReaderTaskEither.ts
@@ -7,6 +7,7 @@ import * as N from '../src/number'
 import * as O from '../src/Option'
 import * as R from '../src/Reader'
 import * as RE from '../src/ReaderEither'
+import * as RIO from '../src/ReaderIO'
 import * as RT from '../src/ReaderTask'
 import * as _ from '../src/ReaderTaskEither'
 import * as RA from '../src/ReadonlyArray'
@@ -230,6 +231,14 @@ describe('ReaderTaskEither', () => {
     U.deepStrictEqual(await _.leftIO(I.of(1))({})(), E.left(1))
   })
 
+  it('rightReaderIO', async () => {
+    U.deepStrictEqual(await _.rightReaderIO(RIO.of(1))({})(), E.right(1))
+  })
+
+  it('leftReaderIO', async () => {
+    U.deepStrictEqual(await _.leftReaderIO(RIO.of(1))({})(), E.left(1))
+  })
+
   it('fromIOEither', async () => {
     U.deepStrictEqual(await _.fromIOEither(() => E.right(1))({})(), E.right(1))
     U.deepStrictEqual(await _.fromIOEither(() => E.left('error'))({})(), E.left('error'))
@@ -489,6 +498,31 @@ describe('ReaderTaskEither', () => {
     U.deepStrictEqual(await pipe(_.right<{}, never, string>('a'), _.chainFirstReaderEitherKW(f))({})(), E.right('a'))
   })
 
+  it('fromReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await _.fromReaderIOK(f)('a')(undefined)(), E.right(1))
+  })
+
+  it('chainReaderIOKW', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.right('a'), _.chainReaderIOKW(f))({})(), E.right(1))
+  })
+
+  it('chainReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.right('a'), _.chainReaderIOK(f))(undefined)(), E.right(1))
+  })
+
+  it('chainFirstReaderIOKW', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.right('a'), _.chainFirstReaderIOKW(f))({})(), E.right('a'))
+  })
+
+  it('chainFirstReaderIOK', async () => {
+    const f = (s: string) => RIO.of(s.length)
+    U.deepStrictEqual(await pipe(_.right('a'), _.chainFirstReaderIOK(f))({})(), E.right('a'))
+  })
+
   // -------------------------------------------------------------------------------------
   // utils
   // -------------------------------------------------------------------------------------