Repository: gcanti/fp-ts
Pull request #746 (2019-02-22 08:17:24)

Monad transformers refactoring


Patch:
diff --git a/docs/StrMap.md b/docs/StrMap.md
index 396339ff..2e01abf7 100644
--- a/docs/StrMap.md
+++ b/docs/StrMap.md
@@ -240,7 +240,7 @@ Added in v1.0.0
 
 ## strmap
 
-**Signature** (constant) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L473-L504)
+**Signature** (constant) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L474-L505)
 
 ```ts
 export const strmap: FunctorWithIndex1<URI, string> &
@@ -256,7 +256,7 @@ Added in v1.0.0
 
 ## collect
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L349-L351)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L350-L352)
 
 ```ts
 export const collect = <A, B>(d: StrMap<A>, f: (k: string, a: A) => B): Array<B> => { ... }
@@ -266,7 +266,7 @@ Added in v1.0.0
 
 ## elem
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L405-L407)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L406-L408)
 
 ```ts
 export function elem<A>(S: Setoid<A>): (a: A, fa: StrMap<A>) => boolean  { ... }
@@ -279,7 +279,7 @@ Added in v1.14.0
 Create a dictionary from a foldable collection of key/value pairs, using the
 specified function to combine values for duplicate keys.
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L337-L343)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L338-L344)
 
 ```ts
 export function fromFoldable<F>(
@@ -302,7 +302,7 @@ Added in v1.0.0
 
 ## getSetoid
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L297-L300)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L298-L301)
 
 ```ts
 export const getSetoid = <A>(S: Setoid<A>): Setoid<StrMap<A>> => { ... }
@@ -314,7 +314,7 @@ Added in v1.0.0
 
 Insert or replace a key/value pair in a map
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L378-L381)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L379-L382)
 
 ```ts
 export const insert = <A>(k: string, a: A, d: StrMap<A>): StrMap<A> => { ... }
@@ -326,7 +326,7 @@ Added in v1.0.0
 
 Test whether a dictionary is empty
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L289-L291)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L290-L292)
 
 ```ts
 export const isEmpty = <A>(d: StrMap<A>): boolean => { ... }
@@ -338,7 +338,7 @@ Added in v1.0.0
 
 Test whether one dictionary contains all of the keys and values contained in another dictionary
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L270-L273)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L271-L274)
 
 ```ts
 export const isSubdictionary = <A>(S: Setoid<A>): ((d1: StrMap<A>, d2: StrMap<A>) => boolean) => { ... }
@@ -350,7 +350,7 @@ Added in v1.0.0
 
 Lookup the value for a key in a dictionary
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L316-L318)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L317-L319)
 
 ```ts
 export const lookup = <A>(k: string, d: StrMap<A>): Option<A> => { ... }
@@ -362,7 +362,7 @@ Added in v1.0.0
 
 Delete a key and value from a map, returning the value as well as the subsequent map
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L398-L400)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L399-L401)
 
 ```ts
 export const pop = <A>(k: string, d: StrMap<A>): Option<[A, StrMap<A>]> => { ... }
@@ -374,7 +374,7 @@ Added in v1.0.0
 
 Delete a key and value from a map
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L388-L391)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L389-L392)
 
 ```ts
 export const remove = <A>(k: string, d: StrMap<A>): StrMap<A> => { ... }
@@ -386,7 +386,7 @@ Added in v1.0.0
 
 Create a dictionary with one key/value pair
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L307-L309)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L308-L310)
 
 ```ts
 export const singleton = <A>(k: string, a: A): StrMap<A> => { ... }
@@ -398,7 +398,7 @@ Added in v1.0.0
 
 Calculate the number of key/value pairs in a dictionary
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L280-L282)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L281-L283)
 
 ```ts
 export const size = <A>(d: StrMap<A>): number => { ... }
@@ -408,7 +408,7 @@ Added in v1.0.0
 
 ## toArray
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L357-L359)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L358-L360)
 
 ```ts
 export const toArray = <A>(d: StrMap<A>): Array<[string, A]> => { ... }
@@ -420,7 +420,7 @@ Added in v1.0.0
 
 Unfolds a dictionary into a list of key/value pairs
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L368-L371)
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L369-L372)
 
 ```ts
 export function toUnfoldable<F>(U: Unfoldable<F>): (<A>(d: StrMap<A>) => HKT<F, [string, A]>)  { ... }
@@ -428,9 +428,11 @@ export function toUnfoldable<F>(U: Unfoldable<F>): (<A>(d: StrMap<A>) => HKT<F,
 
 Added in v1.0.0
 
-## traverseWithKey
+## ~~traverseWithKey~~ (deprecated)
 
-**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L248-L253)
+Use [strmap.traverseWithIndex](#strmap.traversewithindex)
+
+**Signature** (function) [Source](https://github.com/gcanti/fp-ts/blob/master/src/StrMap.ts#L249-L254)
 
 ```ts
 export function traverseWithKey<F>(
diff --git a/examples/ArrayOption.ts b/examples/ArrayOption.ts
index 23d60794..df2356a0 100644
--- a/examples/ArrayOption.ts
+++ b/examples/ArrayOption.ts
@@ -1,7 +1,8 @@
 import { array } from '../src/Array'
 import { Monad1 } from '../src/Monad'
-import { Option } from '../src/Option'
+import { Option, none as optionNone, some as optionSome } from '../src/Option'
 import * as optionT from '../src/OptionT'
+import { identity } from '../src/function'
 
 declare module '../src/HKT' {
   interface URI2HKT<A> {
@@ -9,63 +10,52 @@ declare module '../src/HKT' {
   }
 }
 
-const optionTArray = optionT.getOptionT(array)
-
 export const URI = 'ArrayOption'
 
 export type URI = typeof URI
 
-const optionTfold = optionT.fold(array)
+const T = optionT.getOptionT2v(array)
+const foldT = optionT.fold(array)
 
 export class ArrayOption<A> {
   readonly _A!: A
   readonly _URI!: URI
   constructor(readonly value: Array<Option<A>>) {}
   map<B>(f: (a: A) => B): ArrayOption<B> {
-    return new ArrayOption(optionTArray.map(this.value, f))
+    return new ArrayOption(T.map(this.value, f))
   }
   ap<B>(fab: ArrayOption<(a: A) => B>): ArrayOption<B> {
-    return new ArrayOption(optionTArray.ap<A, B>(fab.value, this.value))
+    return new ArrayOption(T.ap(fab.value, this.value))
   }
   ap_<B, C>(this: ArrayOption<(b: B) => C>, fb: ArrayOption<B>): ArrayOption<C> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => ArrayOption<B>): ArrayOption<B> {
-    return new ArrayOption(optionTArray.chain(a => f(a).value, this.value))
+    return new ArrayOption(T.chain(this.value, a => f(a).value))
+  }
+  fold<R>(onNone: R, onSome: (a: A) => R): Array<R> {
+    return foldT(onNone, onSome, this.value)
   }
-  fold<R>(r: R, some: (a: A) => R): Array<R> {
-    return optionTfold(r, some, this.value)
+  getOrElse(a: A): Array<A> {
+    return this.fold(a, identity)
   }
 }
 
-const map = <A, B>(fa: ArrayOption<A>, f: (a: A) => B): ArrayOption<B> => {
-  return fa.map(f)
-}
+const map = <A, B>(fa: ArrayOption<A>, f: (a: A) => B): ArrayOption<B> => fa.map(f)
 
-const optionTsome = optionT.some(array)
-const of = <A>(a: A): ArrayOption<A> => {
-  return new ArrayOption(optionTsome(a))
-}
+const of = <A>(a: A): ArrayOption<A> => new ArrayOption(T.of(a))
 
-const ap = <A, B>(fab: ArrayOption<(a: A) => B>, fa: ArrayOption<A>): ArrayOption<B> => {
-  return fa.ap(fab)
-}
+const ap = <A, B>(fab: ArrayOption<(a: A) => B>, fa: ArrayOption<A>): ArrayOption<B> => fa.ap(fab)
 
-const chain = <A, B>(fa: ArrayOption<A>, f: (a: A) => ArrayOption<B>): ArrayOption<B> => {
-  return fa.chain(f)
-}
+const chain = <A, B>(fa: ArrayOption<A>, f: (a: A) => ArrayOption<B>): ArrayOption<B> => fa.chain(f)
 
 export const some = of
 
-export const none = new ArrayOption(optionT.none(array)())
+export const none = new ArrayOption(array.of(optionNone))
 
-const optionTfromOption = optionT.fromOption(array)
-export const fromOption = <A>(oa: Option<A>): ArrayOption<A> => {
-  return new ArrayOption(optionTfromOption(oa))
-}
+export const fromOption = <A>(ma: Option<A>): ArrayOption<A> => new ArrayOption(array.of(ma))
 
-const optionTliftF = optionT.liftF(array)
-export const fromArray = <A>(ma: Array<A>): ArrayOption<A> => new ArrayOption(optionTliftF(ma))
+export const fromArray = <A>(ma: Array<A>): ArrayOption<A> => new ArrayOption(ma.map(optionSome))
 
 export const arrayOption: Monad1<URI> = {
   URI,
diff --git a/examples/EitherOption.ts b/examples/EitherOption.ts
index cbbbedf2..c4c43122 100644
--- a/examples/EitherOption.ts
+++ b/examples/EitherOption.ts
@@ -1,7 +1,8 @@
-import * as either from '../src/Either'
+import { Either, either } from '../src/Either'
 import { Monad2 } from '../src/Monad'
-import { Option } from '../src/Option'
+import { Option, none as optionNone, some as optionSome } from '../src/Option'
 import * as optionT from '../src/OptionT'
+import { identity } from '../src/function'
 
 declare module '../src/HKT' {
   interface URI2HKT2<L, A> {
@@ -9,66 +10,53 @@ declare module '../src/HKT' {
   }
 }
 
-const optionTEither = optionT.getOptionT(either.either)
-
 export const URI = 'EitherOption'
 
 export type URI = typeof URI
 
-const optionTfold = optionT.fold(either.either)
+const T = optionT.getOptionT2v(either)
+const foldT = optionT.fold(either)
 
 export class EitherOption<L, A> {
   readonly _A!: A
   readonly _L!: L
   readonly _URI!: URI
-  constructor(readonly value: either.Either<L, Option<A>>) {}
+  constructor(readonly value: Either<L, Option<A>>) {}
   map<B>(f: (a: A) => B): EitherOption<L, B> {
-    return new EitherOption(optionTEither.map(this.value, f))
+    return new EitherOption(T.map(this.value, f))
   }
   ap<B>(fab: EitherOption<L, (a: A) => B>): EitherOption<L, B> {
-    return new EitherOption(optionTEither.ap(fab.value, this.value))
+    return new EitherOption(T.ap(fab.value, this.value))
   }
   ap_<B, C>(this: EitherOption<L, (b: B) => C>, fb: EitherOption<L, B>): EitherOption<L, C> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => EitherOption<L, B>): EitherOption<L, B> {
-    return new EitherOption(optionTEither.chain(a => f(a).value, this.value))
+    return new EitherOption(T.chain(this.value, a => f(a).value))
+  }
+  fold<R>(onNone: R, onSome: (a: A) => R): Either<L, R> {
+    return foldT(onNone, onSome, this.value)
   }
-  fold<R>(r: R, some: (a: A) => R): either.Either<L, R> {
-    return optionTfold(r, some, this.value)
+  getOrElse(a: A): Either<L, A> {
+    return this.fold(a, identity)
   }
 }
 
-const map = <L, A, B>(fa: EitherOption<L, A>, f: (a: A) => B): EitherOption<L, B> => {
-  return fa.map(f)
-}
+const map = <L, A, B>(fa: EitherOption<L, A>, f: (a: A) => B): EitherOption<L, B> => fa.map(f)
 
-const optionTsome = optionT.some(either.either)
-const of = <L, A>(a: A): EitherOption<L, A> => {
-  return new EitherOption(optionTsome(a))
-}
+const of = <L, A>(a: A): EitherOption<L, A> => new EitherOption(T.of(a))
 
-const ap = <L, A, B>(fab: EitherOption<L, (a: A) => B>, fa: EitherOption<L, A>): EitherOption<L, B> => {
-  return fa.ap(fab)
-}
+const ap = <L, A, B>(fab: EitherOption<L, (a: A) => B>, fa: EitherOption<L, A>): EitherOption<L, B> => fa.ap(fab)
 
-const chain = <L, A, B>(fa: EitherOption<L, A>, f: (a: A) => EitherOption<L, B>): EitherOption<L, B> => {
-  return fa.chain(f)
-}
+const chain = <L, A, B>(fa: EitherOption<L, A>, f: (a: A) => EitherOption<L, B>): EitherOption<L, B> => fa.chain(f)
 
 export const some = of
 
-export const none = new EitherOption(optionT.none(either.either)())
+export const none = new EitherOption(either.of(optionNone))
 
-const optionTfromOption = optionT.fromOption(either.either)
-export const fromOption = <L, A>(oa: Option<A>): EitherOption<L, A> => {
-  return new EitherOption(optionTfromOption(oa))
-}
+export const fromOption = <L, A>(ma: Option<A>): EitherOption<L, A> => new EitherOption(either.of(ma))
 
-const optionTliftF = optionT.liftF(either.either)
-export const fromEither = <L, A>(ma: either.Either<L, A>): EitherOption<L, A> => {
-  return new EitherOption(optionTliftF(ma))
-}
+export const fromEither = <L, A>(ma: Either<L, A>): EitherOption<L, A> => new EitherOption(ma.map(optionSome))
 
 export const eitherOption: Monad2<URI> = {
   URI,
diff --git a/examples/Free.ts b/examples/Free.ts
index ec203e78..86d68792 100644
--- a/examples/Free.ts
+++ b/examples/Free.ts
@@ -89,6 +89,7 @@ export function interpretIdentity<A>(fa: InstructionF<A>): Identity<A> {
     case 'RotateRight':
       return identity.of(fa.more(computation.right(fa.position, fa.degree)))
     case 'Show':
+      // tslint:disable-next-line: no-console
       console.log('interpretIdentity', fa.position)
       return identity.of(fa.more)
   }
@@ -103,8 +104,10 @@ const program1 = (start: Position) => {
     .chain(p3 => show(p3))
 }
 
+// tslint:disable-next-line: no-console
 console.log('--program1--')
 const result1 = free.foldFree(identity)(interpretIdentity, program1(start)) // interpretIdentity Position { x: 10, y: 10, heading: Degree { value: 0 } }
+// tslint:disable-next-line: no-console
 console.log(result1.value) // undefined
 
 const nonNegative = (position: Position): option.Option<Position> =>
@@ -119,6 +122,7 @@ export function interpretOption<A>(fa: InstructionF<A>): option.Option<A> {
     case 'RotateRight':
       return nonNegative(computation.right(fa.position, fa.degree)).map(fa.more)
     case 'Show':
+      // tslint:disable-next-line: no-console
       console.log('interpretOption', fa.position)
       return option.some(fa.more)
   }
@@ -133,8 +137,10 @@ const program2 = (start: Position) => {
     .chain(p3 => show(p3))
 }
 
+// tslint:disable-next-line: no-console
 console.log('--program2--')
 const result2 = free.foldFree(option.option)(interpretOption, program2(start))
+// tslint:disable-next-line: no-console
 console.log(result2) // none
 
 // Composing
@@ -218,9 +224,11 @@ const program3 = (start: Position): free.Free<LogoAppFURI, void> => {
 export function penInterpretIdentity<A>(fa: PencilInstructionF<A>): Identity<A> {
   switch (fa._tag) {
     case 'PencilUp':
+      // tslint:disable-next-line: no-console
       console.log(`stop drawing at position ${JSON.stringify(fa.position)}`)
       return identity.of(fa.more)
     case 'PencilDown':
+      // tslint:disable-next-line: no-console
       console.log(`start drawing at position ${JSON.stringify(fa.position)}`)
       return identity.of(fa.more)
   }
@@ -235,6 +243,7 @@ export function logoAppInterpretIdentity<A>(fa: LogoAppF<A>): Identity<A> {
   }
 }
 
+// tslint:disable-next-line: no-console
 console.log('--program3--')
 free.foldFree(identity)(logoAppInterpretIdentity, program3(start))
 /*
@@ -254,14 +263,17 @@ function interpretEither<A>(fa: InstructionF<A>): Either<string, A> {
     case 'RotateRight':
       return either.of(fa.more(computation.right(fa.position, fa.degree)))
     case 'Show':
+      // tslint:disable-next-line: no-console
       console.log('interpretEither', fa.position)
       return either.of(fa.more)
   }
 }
 
+// tslint:disable-next-line: no-console
 console.log('--program1 (Either)--')
 const foldFreeEither = free.foldFree(either)
 const result3 = foldFreeEither(interpretEither, program1(start))
+// tslint:disable-next-line: no-console
 console.log(result3)
 /*
 right(undefined)
diff --git a/examples/Reader.ts b/examples/Reader.ts
index 7950960a..9ef61c96 100644
--- a/examples/Reader.ts
+++ b/examples/Reader.ts
@@ -1,4 +1,4 @@
-import { reader, ask } from '../src/reader'
+import { reader, ask } from '../src/Reader'
 
 // So, what's the Reader monad?
 
@@ -12,7 +12,7 @@ interface Config {
 const x = 1
 
 // Our Reader monad, note it has not been given the context at this point
-const read = reader.of(x)
+const read = reader.of<Config, number>(x)
 
 // Let's start doing calculations with it!
 const read2 = read
@@ -37,6 +37,7 @@ const read2 = read
   })
 
 // what is read2 then?
+// tslint:disable-next-line: no-console
 console.log(read2)
 
 // -> Reader { run: [Function] }
@@ -52,6 +53,7 @@ const config: Config = {
 // let's run our Reader with the stuff in it...
 const output = read2.run(config)
 
+// tslint:disable-next-line: no-console
 console.log(output)
 // -> "Hello horse you are now 112 years old isn't that just lovely?"
 
diff --git a/examples/ReaderEither.ts b/examples/ReaderEither.ts
index c71caf45..30bf1f18 100644
--- a/examples/ReaderEither.ts
+++ b/examples/ReaderEither.ts
@@ -3,7 +3,7 @@ import { Monad3 } from '../src/Monad'
 import { Reader } from '../src/Reader'
 import * as readerT from '../src/ReaderT'
 
-const readerTEither = readerT.getReaderT(either)
+const readerTEither = readerT.getReaderT2v(either)
 
 declare module '../src/HKT' {
   interface URI2HKT3<U, L, A> {
@@ -22,7 +22,7 @@ export class ReaderEither<E, L, A> {
   readonly _URI!: URI
   constructor(readonly run: (e: E) => Either<L, A>) {}
   map<B>(f: (a: A) => B): ReaderEither<E, L, B> {
-    return new ReaderEither(readerTEither.map(f, this.run))
+    return new ReaderEither(readerTEither.map(this.run, f))
   }
   of<E, B>(b: B): ReaderEither<E, L, B> {
     return of(b)
@@ -34,7 +34,7 @@ export class ReaderEither<E, L, A> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => ReaderEither<E, L, B>): ReaderEither<E, L, B> {
-    return new ReaderEither(readerTEither.chain(a => f(a).run, this.run))
+    return new ReaderEither(readerTEither.chain(this.run, a => f(a).run))
   }
 }
 
@@ -54,14 +54,12 @@ const chain = <E, L, A, B>(fa: ReaderEither<E, L, A>, f: (a: A) => ReaderEither<
   return fa.chain(f)
 }
 
-const readerTask = readerT.ask(either)
 export const ask = <E, L>(): ReaderEither<E, L, E> => {
-  return new ReaderEither(readerTask())
+  return new ReaderEither(e => either.of(e))
 }
 
-const readerTasks = readerT.asks(either)
 export const asks = <E, L, A>(f: (e: E) => A): ReaderEither<E, L, A> => {
-  return new ReaderEither(readerTasks(f))
+  return new ReaderEither(e => either.of(f(e)))
 }
 
 export const local = <E>(f: (e: E) => E) => <L, A>(fa: ReaderEither<E, L, A>): ReaderEither<E, L, A> => {
diff --git a/examples/ReaderIO.ts b/examples/ReaderIO.ts
index f618b474..97f6353d 100644
--- a/examples/ReaderIO.ts
+++ b/examples/ReaderIO.ts
@@ -3,7 +3,7 @@ import { Monad2 } from '../src/Monad'
 import { Reader } from '../src/Reader'
 import * as readerT from '../src/ReaderT'
 
-const readerTIO = readerT.getReaderT(io)
+const readerTIO = readerT.getReaderT2v(io)
 
 declare module '../src/HKT' {
   interface URI2HKT2<L, A> {
@@ -21,7 +21,7 @@ export class ReaderIO<E, A> {
   readonly _URI!: URI
   constructor(readonly run: (e: E) => IO<A>) {}
   map<B>(f: (a: A) => B): ReaderIO<E, B> {
-    return new ReaderIO(readerTIO.map(f, this.run))
+    return new ReaderIO(readerTIO.map(this.run, f))
   }
   of<E, B>(b: B): ReaderIO<E, B> {
     return of(b)
@@ -33,7 +33,7 @@ export class ReaderIO<E, A> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => ReaderIO<E, B>): ReaderIO<E, B> {
-    return new ReaderIO(readerTIO.chain(a => f(a).run, this.run))
+    return new ReaderIO(readerTIO.chain(this.run, a => f(a).run))
   }
 }
 
@@ -53,14 +53,12 @@ const chain = <E, A, B>(fa: ReaderIO<E, A>, f: (a: A) => ReaderIO<E, B>): Reader
   return fa.chain(f)
 }
 
-const readerTask = readerT.ask(io)
 export const ask = <E>(): ReaderIO<E, E> => {
-  return new ReaderIO(readerTask())
+  return new ReaderIO(io.of)
 }
 
-const readerTasks = readerT.asks(io)
 export const asks = <E, A>(f: (e: E) => A): ReaderIO<E, A> => {
-  return new ReaderIO(readerTasks(f))
+  return new ReaderIO(e => io.of(f(e)))
 }
 
 export const local = <E>(f: (e: E) => E) => <A>(fa: ReaderIO<E, A>): ReaderIO<E, A> => {
diff --git a/examples/StateIO.ts b/examples/StateIO.ts
index 21e68be4..40f0cb12 100644
--- a/examples/StateIO.ts
+++ b/examples/StateIO.ts
@@ -14,7 +14,7 @@ declare module '../src/HKT' {
   }
 }
 
-const stateTIO = stateT.getStateT(io)
+const stateTIO = stateT.getStateT2v(io)
 
 export const URI = 'StateIO'
 
@@ -35,7 +35,7 @@ export class StateIO<S, A> {
     return this.run(s)[1]
   }
   map<B>(f: (a: A) => B): StateIO<S, B> {
-    return new StateIO(stateTIO.map(f, this.value))
+    return new StateIO(stateTIO.map(this.value, f))
   }
   ap<B>(fab: StateIO<S, (a: A) => B>): StateIO<S, B> {
     return new StateIO(stateTIO.ap(fab.value, this.value))
@@ -44,7 +44,7 @@ export class StateIO<S, A> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => StateIO<S, B>): StateIO<S, B> {
-    return new StateIO(stateTIO.chain(a => f(a).value, this.value))
+    return new StateIO(stateTIO.chain(this.value, a => f(a).value))
   }
 }
 
diff --git a/examples/StateTaskEither.ts b/examples/StateTaskEither.ts
index b455c5d1..6424864b 100644
--- a/examples/StateTaskEither.ts
+++ b/examples/StateTaskEither.ts
@@ -11,7 +11,7 @@ declare module '../src/HKT' {
   }
 }
 
-const stateTIO = stateT.getStateT(taskEither)
+const T = stateT.getStateT2v(taskEither)
 
 export const URI = 'StateTaskEither'
 
@@ -33,72 +33,62 @@ export class StateTaskEither<S, L, A> {
     return this.run(s).then(e => e.map(([_, s]) => s))
   }
   map<B>(f: (a: A) => B): StateTaskEither<S, L, B> {
-    return new StateTaskEither(stateTIO.map(f, this.value))
+    return new StateTaskEither(T.map(this.value, f))
   }
   ap<B>(fab: StateTaskEither<S, L, (a: A) => B>): StateTaskEither<S, L, B> {
-    return new StateTaskEither(stateTIO.ap(fab.value, this.value))
+    return new StateTaskEither(T.ap(fab.value, this.value))
   }
   ap_<B, C>(this: StateTaskEither<S, L, (b: B) => C>, fb: StateTaskEither<S, L, B>): StateTaskEither<S, L, C> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => StateTaskEither<S, L, B>): StateTaskEither<S, L, B> {
-    return new StateTaskEither(stateTIO.chain(a => f(a).value, this.value))
+    return new StateTaskEither(T.chain(this.value, a => f(a).value))
   }
   orElse<M>(f: (l: L) => StateTaskEither<S, M, A>): StateTaskEither<S, M, A> {
     return new StateTaskEither(s => this.value(s).orElse(l => f(l).value(s)))
   }
 }
 
-const map = <S, L, A, B>(fa: StateTaskEither<S, L, A>, f: (a: A) => B): StateTaskEither<S, L, B> => {
-  return fa.map(f)
-}
+const map = <S, L, A, B>(fa: StateTaskEither<S, L, A>, f: (a: A) => B): StateTaskEither<S, L, B> => fa.map(f)
 
-const of = <S, L, A>(a: A): StateTaskEither<S, L, A> => {
-  return new StateTaskEither(stateTIO.of(a))
-}
+const of = <S, L, A>(a: A): StateTaskEither<S, L, A> => new StateTaskEither(T.of(a))
 
 const ap = <S, L, A, B>(
   fab: StateTaskEither<S, L, (a: A) => B>,
   fa: StateTaskEither<S, L, A>
-): StateTaskEither<S, L, B> => {
-  return fa.ap(fab)
-}
+): StateTaskEither<S, L, B> => fa.ap(fab)
 
 const chain = <S, L, A, B>(
   fa: StateTaskEither<S, L, A>,
   f: (a: A) => StateTaskEither<S, L, B>
-): StateTaskEither<S, L, B> => {
-  return fa.chain(f)
-}
+): StateTaskEither<S, L, B> => fa.chain(f)
 
-const stateTget = stateT.get(taskEither)
-export const get = <L, S>(): StateTaskEither<S, L, S> => {
-  return new StateTaskEither<S, L, S>(stateTget())
-}
+const getT = stateT.get2v(taskEither)
+export const get = <L, S>(): StateTaskEither<S, L, S> => new StateTaskEither<S, L, S>(getT)
 
-const stateTput = stateT.put(taskEither)
+const putT = stateT.put(taskEither)
 export const put = <L, S>(s: S): StateTaskEither<S, L, void> => {
-  return new StateTaskEither<S, L, void>(stateTput(s))
+  return new StateTaskEither<S, L, void>(putT(s))
 }
 
-const stateTmodify = stateT.modify(taskEither)
+const modifyT = stateT.modify(taskEither)
 export const modify = <L, S>(f: Endomorphism<S>): StateTaskEither<S, L, void> => {
-  return new StateTaskEither<S, L, void>(stateTmodify(f))
+  return new StateTaskEither<S, L, void>(modifyT(f))
 }
 
-const stateTgets = stateT.gets(taskEither)
+const getsT = stateT.gets(taskEither)
 export const gets = <S, L, A>(f: (s: S) => A): StateTaskEither<S, L, A> => {
-  return new StateTaskEither<S, L, A>(stateTgets(f))
+  return new StateTaskEither<S, L, A>(getsT(f))
 }
 
-const stateTliftF = stateT.liftF(taskEither)
+const liftT = stateT.liftF(taskEither)
 export const fromTaskEither = <S, L, A>(fa: TaskEither<L, A>): StateTaskEither<S, L, A> => {
-  return new StateTaskEither(stateTliftF(fa))
+  return new StateTaskEither(liftT(fa))
 }
 
-const stateTfromState = stateT.fromState(taskEither)
+const fromStateT = stateT.fromState(taskEither)
 export const fromState = <S, A, L>(fa: State<S, A>): StateTaskEither<S, L, A> => {
-  return new StateTaskEither(stateTfromState(fa))
+  return new StateTaskEither(fromStateT(fa))
 }
 
 export const stateTaskEither: Monad3<URI> = {
diff --git a/examples/TaskOption.ts b/examples/TaskOption.ts
index 16e257db..e0ff3721 100644
--- a/examples/TaskOption.ts
+++ b/examples/TaskOption.ts
@@ -1,8 +1,8 @@
 import { Monad1 } from '../src/Monad'
-import { Option, fromEither } from '../src/Option'
+import { Option, fromEither, none as optionNone, some as optionSome } from '../src/Option'
 import * as optionT from '../src/OptionT'
 import { Task, task, tryCatch as tryCatchTask } from '../src/Task'
-import { Lazy } from '../src/function'
+import { Lazy, identity } from '../src/function'
 
 declare module '../src/HKT' {
   interface URI2HKT<A> {
@@ -10,13 +10,12 @@ declare module '../src/HKT' {
   }
 }
 
-const optionTTask = optionT.getOptionT(task)
-
 export const URI = 'TaskOption'
 
 export type URI = typeof URI
 
-const optionTfold = optionT.fold(task)
+const T = optionT.getOptionT2v(task)
+const foldT = optionT.fold(task)
 
 export class TaskOption<A> {
   readonly _A!: A
@@ -26,61 +25,43 @@ export class TaskOption<A> {
     return this.value.run()
   }
   map<B>(f: (a: A) => B): TaskOption<B> {
-    return new TaskOption(optionTTask.map(this.value, f))
+    return new TaskOption(T.map(this.value, f))
   }
   ap<B>(fab: TaskOption<(a: A) => B>): TaskOption<B> {
-    return new TaskOption(optionTTask.ap<A, B>(fab.value, this.value))
+    return new TaskOption(T.ap(fab.value, this.value))
   }
   ap_<B, C>(this: TaskOption<(b: B) => C>, fb: TaskOption<B>): TaskOption<C> {
     return fb.ap(this)
   }
   chain<B>(f: (a: A) => TaskOption<B>): TaskOption<B> {
-    return new TaskOption(optionTTask.chain(a => f(a).value, this.value))
+    return new TaskOption(T.chain(this.value, a => f(a).value))
   }
-  fold<R>(r: R, some: (a: A) => R): Task<R> {
-    return optionTfold(r, some, this.value)
+  fold<R>(onNone: R, onSome: (a: A) => R): Task<R> {
+    return foldT(onNone, onSome, this.value)
   }
-  orElse(f: () => TaskOption<A>): TaskOption<A> {
-    return new TaskOption(this.value.chain(e => e.fold(f().value, a => optionTTask.of(a))))
+  getOrElse(a: A): Task<A> {
+    return this.fold(a, identity)
   }
 }
 
-const map = <A, B>(fa: TaskOption<A>, f: (a: A) => B): TaskOption<B> => {
-  return fa.map(f)
-}
+const map = <A, B>(fa: TaskOption<A>, f: (a: A) => B): TaskOption<B> => fa.map(f)
 
-const optionTsome = optionT.some(task)
-const of = <A>(a: A): TaskOption<A> => new TaskOption(optionTsome(a))
+const of = <A>(a: A): TaskOption<A> => new TaskOption(T.of(a))
 
-const ap = <A, B>(fab: TaskOption<(a: A) => B>, fa: TaskOption<A>): TaskOption<B> => {
-  return fa.ap(fab)
-}
+const ap = <A, B>(fab: TaskOption<(a: A) => B>, fa: TaskOption<A>): TaskOption<B> => fa.ap(fab)
 
-const chain = <A, B>(fa: TaskOption<A>, f: (a: A) => TaskOption<B>): TaskOption<B> => {
-  return fa.chain(f)
-}
+const chain = <A, B>(fa: TaskOption<A>, f: (a: A) => TaskOption<B>): TaskOption<B> => fa.chain(f)
 
 export const some = of
 
-export const none = new TaskOption(optionT.none(task)())
+export const none = new TaskOption(task.of(optionNone))
 
-const optionTfromOption = optionT.fromOption(task)
-export const fromOption = <A>(oa: Option<A>): TaskOption<A> => {
-  return new TaskOption(optionTfromOption(oa))
-}
+export const fromOption = <A>(ma: Option<A>): TaskOption<A> => new TaskOption(task.of(ma))
 
-const optionTliftF = optionT.liftF(task)
-export const fromTask = <A>(ma: Task<A>): TaskOption<A> => {
-  return new TaskOption(optionTliftF(ma))
-}
-
-export const orElse = <A>(f: () => TaskOption<A>) => (fa: TaskOption<A>): TaskOption<A> => {
-  return fa.orElse(f)
-}
+export const fromTask = <A>(ma: Task<A>): TaskOption<A> => new TaskOption(ma.map(optionSome))
 
-export const tryCatch = <A>(f: Lazy<Promise<A>>): TaskOption<A> => {
-  return new TaskOption(tryCatchTask(f, () => undefined).map(e => fromEither(e)))
-}
+export const tryCatch = <A>(f: Lazy<Promise<A>>): TaskOption<A> =>
+  new TaskOption(tryCatchTask(f, () => undefined).map(fromEither))
 
 export const taskOption: Monad1<URI> = {
   URI,
diff --git a/examples/TheseOption.ts b/examples/TheseOption.ts
index 897b755c..a21f4072 100644
--- a/examples/TheseOption.ts
+++ b/examples/TheseOption.ts
@@ -1,5 +1,5 @@
 import { Monad2C } from '../src/Monad'
-import { Option } from '../src/Option'
+import { Option, some as optionSome } from '../src/Option'
 import * as optionT from '../src/OptionT'
 import { These, URI as TheseURI } from '../src/These'
 import { phantom } from '../src/function'
@@ -21,25 +21,19 @@ export class TheseOption<L, A> {
   constructor(readonly value: These<L, Option<A>>) {}
 }
 
-export const getMonad = <L>(these: Monad2C<TheseURI, L>): Monad2C<URI, L> => {
-  const optionTThese = optionT.getOptionT(these)
+export const getMonad = <L>(M: Monad2C<TheseURI, L>): Monad2C<URI, L> => {
+  const T = optionT.getOptionT2v(M)
 
-  const map = <A, B>(fa: TheseOption<L, A>, f: (a: A) => B): TheseOption<L, B> => {
-    return new TheseOption(optionTThese.map(fa.value, f))
-  }
+  const map = <A, B>(fa: TheseOption<L, A>, f: (a: A) => B): TheseOption<L, B> => new TheseOption(T.map(fa.value, f))
 
-  const optionTsome = optionT.some(these)
-  const of = <A>(a: A): TheseOption<L, A> => {
-    return new TheseOption(optionTsome(a))
-  }
+  const of = <A>(a: A): TheseOption<L, A> => new TheseOption(T.of(a))
 
-  const ap = <A, B>(fab: TheseOption<L, (a: A) => B>, fa: TheseOption<L, A>): TheseOption<L, B> => {
-    return new TheseOption(optionTThese.ap(fab.value, fa.value))
-  }
+  const ap = <A, B>(fab: TheseOption<L, (a: A) => B>, fa: TheseOption<L, A>): TheseOption<L, B> =>
+    new TheseOption(T.ap(fab.value, fa.value))
+
+  const chain = <A, B>(fa: TheseOption<L, A>, f: (a: A) => TheseOption<L, B>): TheseOption<L, B> =>
+    new TheseOption(T.chain(fa.value, a => f(a).value))
 
-  const chain = <A, B>(fa: TheseOption<L, A>, f: (a: A) => TheseOption<L, B>): TheseOption<L, B> => {
-    return new TheseOption(optionTThese.chain(a => f(a).value, fa.value))
-  }
   return {
     URI,
     _L: phantom,
@@ -50,23 +44,17 @@ export const getMonad = <L>(these: Monad2C<TheseURI, L>): Monad2C<URI, L> => {
   }
 }
 
-export const fold = <L>(
-  these: Monad2C<TheseURI, L>
+export const getFold = <L>(
+  M: Monad2C<TheseURI, L>
 ): (<A, R>(r: R, some: (a: A) => R, fa: TheseOption<L, A>) => These<L, R>) => {
-  const optionTfold = optionT.fold(these)
+  const optionTfold = optionT.fold(M)
   return (r, some, fa) => optionTfold(r, some, fa.value)
 }
 
-export const some = <L>(M: Monad2C<URI, L>): (<A>(a: A) => TheseOption<L, A>) => {
+export const getSome = <L>(M: Monad2C<URI, L>): (<A>(a: A) => TheseOption<L, A>) => {
   return M.of
 }
 
-export const fromOption = <L>(these: Monad2C<TheseURI, L>): (<A>(fa: Option<A>) => TheseOption<L, A>) => {
-  const optionTfromOption = optionT.fromOption(these)
-  return oa => new TheseOption(optionTfromOption(oa))
-}
-
-export const liftF = <L>(these: Monad2C<TheseURI, L>): (<A>(fa: These<L, A>) => TheseOption<L, A>) => {
-  const optionTliftF = optionT.liftF(these)
-  return ma => new TheseOption(optionTliftF(ma))
+export const getFromThese = <L, A>(fa: These<L, A>): TheseOption<L, A> => {
+  return new TheseOption(fa.map(optionSome))
 }
diff --git a/examples/debugging-with-Trace.ts b/examples/debugging-with-Trace.ts
index 1cb3011b..f730f1a3 100644
--- a/examples/debugging-with-Trace.ts
+++ b/examples/debugging-with-Trace.ts
@@ -9,6 +9,7 @@ import { spy, trace, traceA, traceM } from '../src/Trace'
 
 const foo = left<string, number>('foo')
 const bar = spy(foo.mapLeft(s => s.length))
+// tslint:disable-next-line: no-console
 console.log(bar)
 // => left(3)
 
@@ -17,6 +18,7 @@ console.log(bar)
 //
 
 const bar2 = foo.mapLeft(s => trace('mapping the left side', () => s.length))
+// tslint:disable-next-line: no-console
 console.log(bar2)
 // => 'mapping the left side'
 
@@ -42,6 +44,7 @@ const baz: Option<number> = some([1, 2, 3])
   .chain(traceMOption)
   .chain(head)
   .chain(traceMOption)
+// tslint:disable-next-line: no-console
 console.log(baz)
 // => [1, 2, 3]
 // => 1
diff --git a/examples/mtl.ts b/examples/mtl.ts
index f29db55a..b3d6b1d9 100644
--- a/examples/mtl.ts
+++ b/examples/mtl.ts
@@ -100,6 +100,7 @@ const monadAppTask: MonadApp1<TaskURI> = {
   ...monadFBTask
 }
 
+// tslint:disable-next-line: no-floating-promises
 likePost(monadAppTask)('session123')('https://me.com/1')
   .run()
   // tslint:disable-next-line:no-console
@@ -143,11 +144,13 @@ const monadAppReaderTaskEither: MonadApp3C<ReaderTaskEitherURI, Env, Error> = {
 
 const ma = likePost(monadAppReaderTaskEither)('session123')('https://me.com/1')
 
+// tslint:disable-next-line: no-floating-promises
 ma.run({ error: true })
   // tslint:disable-next-line:no-console
   .then(result => console.log('ReaderTaskEither 2', result))
 // => ReaderTaskEither 2 left(Error: validateUser error)
 
+// tslint:disable-next-line: no-floating-promises
 ma.run({ error: false })
   // tslint:disable-next-line:no-console
   .then(result => console.log('ReaderTaskEither 1', result))
diff --git a/examples/tsconfig.json b/examples/tsconfig.json
new file mode 100644
index 00000000..5dc8cdd5
--- /dev/null
+++ b/examples/tsconfig.json
@@ -0,0 +1,7 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "noEmit": true
+  },
+  "include": ["./**/*"]
+}
diff --git a/src/EitherT.ts b/src/EitherT.ts
index c8dd99a6..bc13c89a 100644
--- a/src/EitherT.ts
+++ b/src/EitherT.ts
@@ -12,14 +12,65 @@ import { Functor, Functor1, Functor2 } from './Functor'
 import { HKT, Type, Type2, URIS, URIS2 } from './HKT'
 import { Monad, Monad1, Monad2 } from './Monad'
 
+export interface EitherT2v<F> extends ApplicativeComposition<F, URI> {
+  readonly chain: <L, A, B>(fa: HKT<F, Either<L, A>>, f: (a: A) => HKT<F, Either<L, B>>) => HKT<F, Either<L, B>>
+}
+
+export interface EitherT2v1<F extends URIS> extends ApplicativeComposition12<F, URI> {
+  readonly chain: <L, A, B>(fa: Type<F, Either<L, A>>, f: (a: A) => Type<F, Either<L, B>>) => Type<F, Either<L, B>>
+}
+
+export interface EitherT2v2<F extends URIS2> extends ApplicativeComposition22<F, URI> {
+  readonly chain: <L, M, A, B>(
+    fa: Type2<F, M, Either<L, A>>,
+    f: (a: A) => Type2<F, M, Either<L, B>>
+  ) => Type2<F, M, Either<L, B>>
+}
+
+/**
+ * @since 1.0.0
+ */
+export function fold<F extends URIS2>(
+  F: Functor2<F>
+): <R, L, M, A>(left: (l: L) => R, right: (a: A) => R, fa: Type2<F, M, Either<L, A>>) => Type2<F, M, R>
+export function fold<F extends URIS>(
+  F: Functor1<F>
+): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: Type<F, Either<L, A>>) => Type<F, R>
+export function fold<F>(
+  F: Functor<F>
+): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: HKT<F, Either<L, A>>) => HKT<F, R>
+export function fold<F>(
+  F: Functor<F>
+): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: HKT<F, Either<L, A>>) => HKT<F, R> {
+  return (left, right, fa) => F.map(fa, e => (e.isLeft() ? left(e.value) : right(e.value)))
+}
+
+/**
+ * @since 1.14.0
+ */
+export function getEitherT2v<M extends URIS2>(M: Monad2<M>): EitherT2v2<M>
+export function getEitherT2v<M extends URIS>(M: Monad1<M>): EitherT2v1<M>
+export function getEitherT2v<M>(M: Monad<M>): EitherT2v<M>
+export function getEitherT2v<M>(M: Monad<M>): EitherT2v<M> {
+  const applicativeComposition = getApplicativeComposition(M, either)
+
+  return {
+    ...applicativeComposition,
+    chain: (fa, f) => M.chain(fa, e => (e.isLeft() ? M.of(eitherLeft(e.value)) : f(e.value)))
+  }
+}
+
+/** @deprecated */
 export interface EitherT<F> extends ApplicativeComposition<F, URI> {
   readonly chain: <L, A, B>(f: (a: A) => HKT<F, Either<L, B>>, fa: HKT<F, Either<L, A>>) => HKT<F, Either<L, B>>
 }
 
+/** @deprecated */
 export interface EitherT1<F extends URIS> extends ApplicativeComposition12<F, URI> {
   readonly chain: <L, A, B>(f: (a: A) => Type<F, Either<L, B>>, fa: Type<F, Either<L, A>>) => Type<F, Either<L, B>>
 }
 
+/** @deprecated */
 export interface EitherT2<F extends URIS2> extends ApplicativeComposition22<F, URI> {
   readonly chain: <L, M, A, B>(
     f: (a: A) => Type2<F, M, Either<L, B>>,
@@ -28,77 +79,109 @@ export interface EitherT2<F extends URIS2> extends ApplicativeComposition22<F, U
 }
 
 /**
+ * Use {@link getEitherT2v} instead
  * @since 1.0.0
+ * @deprecated
  */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS2>(F: Monad2<F>): EitherT2<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS>(F: Monad1<F>): EitherT1<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F>(F: Monad<F>): EitherT<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F>(F: Monad<F>): EitherT<F>['chain'] {
   return (f, fa) => F.chain(fa, e => (e.isLeft() ? F.of(eitherLeft(e.value)) : f(e.value)))
 }
 
 /**
+ * Use {@link getEitherT2v} instead
  * @since 1.0.0
+ * @deprecated
+ */
+// tslint:disable-next-line: deprecation
+export function getEitherT<M extends URIS2>(M: Monad2<M>): EitherT2<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getEitherT<M extends URIS>(M: Monad1<M>): EitherT1<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getEitherT<M>(M: Monad<M>): EitherT<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getEitherT<M>(M: Monad<M>): EitherT<M> {
+  const applicativeComposition = getApplicativeComposition(M, either)
+
+  return {
+    ...applicativeComposition,
+    // tslint:disable-next-line: deprecation
+    chain: chain(M)
+  }
+}
+
+/**
+ * @since 1.0.0
+ * @deprecated
  */
 export function right<F extends URIS2>(F: Functor2<F>): <L, M, A>(fa: Type2<F, M, A>) => Type2<F, M, Either<L, A>>
+/** @deprecated */
 export function right<F extends URIS>(F: Functor1<F>): <L, A>(fa: Type<F, A>) => Type<F, Either<L, A>>
+/** @deprecated */
 export function right<F>(F: Functor<F>): <L, A>(fa: HKT<F, A>) => HKT<F, Either<L, A>>
+/** @deprecated */
 export function right<F>(F: Functor<F>): <L, A>(fa: HKT<F, A>) => HKT<F, Either<L, A>> {
   return ma => F.map(ma, a => eitherRight(a))
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function left<F extends URIS2>(F: Functor2<F>): <L, M, A>(fl: Type2<F, M, L>) => Type2<F, M, Either<L, A>>
+/** @deprecated */
 export function left<F extends URIS>(F: Functor1<F>): <L, A>(fl: Type<F, L>) => Type<F, Either<L, A>>
+/** @deprecated */
 export function left<F>(F: Functor<F>): <L, A>(fl: HKT<F, L>) => HKT<F, Either<L, A>>
+/** @deprecated */
 export function left<F>(F: Functor<F>): <L, A>(fl: HKT<F, L>) => HKT<F, Either<L, A>> {
   return ml => F.map(ml, l => eitherLeft(l))
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function fromEither<F extends URIS2>(
   F: Applicative2<F>
 ): <L, M, A>(fa: Either<L, A>) => Type2<F, M, Either<L, A>>
+/** @deprecated */
 export function fromEither<F extends URIS>(F: Applicative1<F>): <L, A>(fa: Either<L, A>) => Type<F, Either<L, A>>
+/** @deprecated */
 export function fromEither<F>(F: Applicative<F>): <L, A>(fa: Either<L, A>) => HKT<F, Either<L, A>>
+/** @deprecated */
 export function fromEither<F>(F: Applicative<F>): <L, A>(fa: Either<L, A>) => HKT<F, Either<L, A>> {
-  return oa => F.of(oa)
-}
-
-/**
- * @since 1.0.0
- */
-export function fold<F extends URIS2>(
-  F: Functor2<F>
-): <R, L, M, A>(left: (l: L) => R, right: (a: A) => R, fa: Type2<F, M, Either<L, A>>) => Type2<F, M, R>
-export function fold<F extends URIS>(
-  F: Functor1<F>
-): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: Type<F, Either<L, A>>) => Type<F, R>
-export function fold<F>(
-  F: Functor<F>
-): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: HKT<F, Either<L, A>>) => HKT<F, R>
-export function fold<F>(
-  F: Functor<F>
-): <R, L, A>(left: (l: L) => R, right: (a: A) => R, fa: HKT<F, Either<L, A>>) => HKT<F, R> {
-  return (left, right, fa) => F.map(fa, e => (e.isLeft() ? left(e.value) : right(e.value)))
+  return F.of
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function mapLeft<F extends URIS2>(
   F: Functor2<F>
 ): <N, L, M>(f: (l: L) => N) => <A>(fa: Type2<F, M, Either<L, A>>) => Type2<F, M, Either<N, A>>
+/** @deprecated */
 export function mapLeft<F extends URIS>(
   F: Functor1<F>
 ): <N, L>(f: (l: L) => N) => <A>(fa: Type<F, Either<L, A>>) => Type<F, Either<N, A>>
+/** @deprecated */
 export function mapLeft<F>(
   F: Functor<F>
 ): <N, L>(f: (l: L) => N) => <A>(fa: HKT<F, Either<L, A>>) => HKT<F, Either<N, A>>
+/** @deprecated */
 export function mapLeft<F>(
   F: Functor<F>
 ): <N, L>(f: (l: L) => N) => <A>(fa: HKT<F, Either<L, A>>) => HKT<F, Either<N, A>> {
@@ -107,33 +190,22 @@ export function mapLeft<F>(
 
 /**
  * @since 1.2.0
+ * @deprecated
  */
 export function bimap<F extends URIS2>(
   F: Functor2<F>
 ): <M, L, V, A, B>(fa: Type2<F, M, Either<L, A>>, f: (l: L) => V, g: (a: A) => B) => Type2<F, M, Either<V, B>>
+/** @deprecated */
 export function bimap<F extends URIS>(
   F: Functor1<F>
 ): <L, V, A, B>(fa: Type<F, Either<L, A>>, f: (l: L) => V, g: (a: A) => B) => Type<F, Either<V, B>>
+/** @deprecated */
 export function bimap<F>(
   F: Functor<F>
 ): <L, V, A, B>(fa: HKT<F, Either<L, A>>, f: (l: L) => V, g: (a: A) => B) => HKT<F, Either<V, B>>
+/** @deprecated */
 export function bimap<F>(
   F: Functor<F>
 ): <L, V, A, B>(fa: HKT<F, Either<L, A>>, f: (l: L) => V, g: (a: A) => B) => HKT<F, Either<V, B>> {
   return (fa, f, g) => F.map(fa, e => e.bimap(f, g))
 }
-
-/**
- * @since 1.0.0
- */
-export function getEitherT<M extends URIS2>(M: Monad2<M>): EitherT2<M>
-export function getEitherT<M extends URIS>(M: Monad1<M>): EitherT1<M>
-export function getEitherT<M>(M: Monad<M>): EitherT<M>
-export function getEitherT<M>(M: Monad<M>): EitherT<M> {
-  const applicativeComposition = getApplicativeComposition(M, either)
-
-  return {
-    ...applicativeComposition,
-    chain: chain(M)
-  }
-}
diff --git a/src/IOEither.ts b/src/IOEither.ts
index 362a02b0..defcc4ff 100644
--- a/src/IOEither.ts
+++ b/src/IOEither.ts
@@ -1,5 +1,5 @@
 import { Bifunctor2 } from './Bifunctor'
-import { Either, left as eitherLeft, tryCatch2v as eitherTryCatch2v, toError } from './Either'
+import { Either, left as eitherLeft, right as eitherRight, tryCatch2v as eitherTryCatch2v, toError } from './Either'
 import * as eitherT from './EitherT'
 import { Monad2 } from './Monad'
 import { IO, io } from './IO'
@@ -12,15 +12,12 @@ declare module './HKT' {
   }
 }
 
-const eitherTIO = eitherT.getEitherT(io)
-
 export const URI = 'IOEither'
 
 export type URI = typeof URI
 
-const eitherTfold = eitherT.fold(io)
-const eitherTmapLeft = eitherT.mapLeft(io)
-const eitherTbimap = eitherT.bimap(io)
+const T = eitherT.getEitherT2v(io)
+const foldT = eitherT.fold(io)
 
 /**
  * `IOEither<L, A>` represents a synchronous computation that either yields a value of type `A` or fails yielding an
@@ -41,10 +38,10 @@ export class IOEither<L, A> {
     return this.value.run()
   }
   map<B>(f: (a: A) => B): IOEither<L, B> {
-    return new IOEither(eitherTIO.map(this.value, f))
+    return new IOEither(T.map(this.value, f))
   }
   ap<B>(fab: IOEither<L, (a: A) => B>): IOEither<L, B> {
-    return new IOEither(eitherTIO.ap(fab.value, this.value))
+    return new IOEither(T.ap(fab.value, this.value))
   }
   /**
    * Flipped version of {@link ap}
@@ -65,22 +62,22 @@ export class IOEither<L, A> {
     return fb.ap(this.map(constIdentity as () => (b: B) => B))
   }
   chain<B>(f: (a: A) => IOEither<L, B>): IOEither<L, B> {
-    return new IOEither(eitherTIO.chain(a => f(a).value, this.value))
+    return new IOEither(T.chain(this.value, a => f(a).value))
   }
   fold<R>(left: (l: L) => R, right: (a: A) => R): IO<R> {
-    return eitherTfold(left, right, this.value)
+    return foldT(left, right, this.value)
   }
   mapLeft<M>(f: (l: L) => M): IOEither<M, A> {
-    return new IOEither(eitherTmapLeft(f)(this.value))
+    return new IOEither(this.value.map(e => e.mapLeft(f)))
   }
   orElse<M>(f: (l: L) => IOEither<M, A>): IOEither<M, A> {
-    return new IOEither(this.value.chain(e => e.fold(l => f(l).value, a => eitherTIO.of(a))))
+    return new IOEither(this.value.chain(e => e.fold(l => f(l).value, a => T.of(a))))
   }
   alt(fy: IOEither<L, A>): IOEither<L, A> {
     return this.orElse(() => fy)
   }
   bimap<V, B>(f: (l: L) => V, g: (a: A) => B): IOEither<V, B> {
-    return new IOEither(eitherTbimap(this.value, f, g))
+    return new IOEither(this.value.map(e => e.bimap(f, g)))
   }
 }
 
@@ -89,7 +86,7 @@ const map = <L, A, B>(fa: IOEither<L, A>, f: (a: A) => B): IOEither<L, B> => {
 }
 
 const of = <L, A>(a: A): IOEither<L, A> => {
-  return new IOEither(eitherTIO.of(a))
+  return new IOEither(T.of(a))
 }
 
 const ap = <L, A, B>(fab: IOEither<L, (a: A) => B>, fa: IOEither<L, A>): IOEither<L, B> => {
@@ -108,31 +105,25 @@ const bimap = <L, V, A, B>(fa: IOEither<L, A>, f: (l: L) => V, g: (a: A) => B):
   return fa.bimap(f, g)
 }
 
-const eitherTright = eitherT.right(io)
-
 /**
  * @since 1.6.0
  */
 export const right = <L, A>(fa: IO<A>): IOEither<L, A> => {
-  return new IOEither(eitherTright(fa))
+  return new IOEither(fa.map(a => eitherRight(a)))
 }
 
-const eitherTleft = eitherT.left(io)
-
 /**
  * @since 1.6.0
  */
 export const left = <L, A>(fa: IO<L>): IOEither<L, A> => {
-  return new IOEither(eitherTleft(fa))
+  return new IOEither(fa.map(a => eitherLeft(a)))
 }
 
-const eitherTfromEither = eitherT.fromEither(io)
-
 /**
  * @since 1.6.0
  */
 export const fromEither = <L, A>(fa: Either<L, A>): IOEither<L, A> => {
-  return new IOEither(eitherTfromEither(fa))
+  return new IOEither(io.of(fa))
 }
 
 /**
diff --git a/src/OptionT.ts b/src/OptionT.ts
index c551b779..322d5cf9 100644
--- a/src/OptionT.ts
+++ b/src/OptionT.ts
@@ -16,22 +16,87 @@ import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 import { Monad, Monad1, Monad2, Monad2C, Monad3C } from './Monad'
 import { Option, URI, none as optionNone, option, some as optionSome } from './Option'
 
+export interface OptionT2v<M> extends ApplicativeComposition<M, URI> {
+  readonly chain: <A, B>(fa: HKT<M, Option<A>>, f: (a: A) => HKT<M, Option<B>>) => HKT<M, Option<B>>
+}
+
+export interface OptionT2v1<M extends URIS> extends ApplicativeComposition11<M, URI> {
+  readonly chain: <A, B>(fa: Type<M, Option<A>>, f: (a: A) => Type<M, Option<B>>) => Type<M, Option<B>>
+}
+
+export interface OptionT2v2<M extends URIS2> extends ApplicativeComposition21<M, URI> {
+  readonly chain: <L, A, B>(fa: Type2<M, L, Option<A>>, f: (a: A) => Type2<M, L, Option<B>>) => Type2<M, L, Option<B>>
+}
+
+export interface OptionT2v2C<M extends URIS2, L> extends ApplicativeComposition2C1<M, URI, L> {
+  readonly chain: <A, B>(fa: Type2<M, L, Option<A>>, f: (a: A) => Type2<M, L, Option<B>>) => Type2<M, L, Option<B>>
+}
+
+export interface OptionT2v3C<M extends URIS3, U, L> extends ApplicativeComposition3C1<M, URI, U, L> {
+  readonly chain: <A, B>(
+    fa: Type3<M, U, L, Option<A>>,
+    f: (a: A) => Type3<M, U, L, Option<B>>
+  ) => Type3<M, U, L, Option<B>>
+}
+
+/**
+ * @since 1.0.0
+ */
+export function fold<F extends URIS3, U, L>(
+  F: Functor3C<F, U, L>
+): <R, A>(onNone: R, onSome: (a: A) => R, fa: Type3<F, U, L, Option<A>>) => Type3<F, U, L, R>
+export function fold<F extends URIS2>(
+  F: Functor2<F>
+): <L, R, A>(onNone: R, onSome: (a: A) => R, fa: Type2<F, L, Option<A>>) => Type2<F, L, R>
+export function fold<F extends URIS2, L>(
+  F: Functor2C<F, L>
+): <R, A>(onNone: R, onSome: (a: A) => R, fa: Type2<F, L, Option<A>>) => Type2<F, L, R>
+export function fold<F extends URIS>(
+  F: Functor1<F>
+): <R, A>(onNone: R, onSome: (a: A) => R, fa: Type<F, Option<A>>) => Type<F, R>
+export function fold<F>(F: Functor<F>): <R, A>(onNone: R, onSome: (a: A) => R, fa: HKT<F, Option<A>>) => HKT<F, R>
+export function fold<F>(F: Functor<F>): <R, A>(onNone: R, onSome: (a: A) => R, fa: HKT<F, Option<A>>) => HKT<F, R> {
+  return (onNone, onSome, fa) => F.map(fa, o => (o.isNone() ? onNone : onSome(o.value)))
+}
+
+/**
+ * @since 1.14.0
+ */
+export function getOptionT2v<M extends URIS3, U, L>(M: Monad3C<M, U, L>): OptionT2v3C<M, U, L>
+export function getOptionT2v<M extends URIS2>(M: Monad2<M>): OptionT2v2<M>
+export function getOptionT2v<M extends URIS2, L>(M: Monad2C<M, L>): OptionT2v2C<M, L>
+export function getOptionT2v<M extends URIS>(M: Monad1<M>): OptionT2v1<M>
+export function getOptionT2v<M>(M: Monad<M>): OptionT2v<M>
+export function getOptionT2v<M>(M: Monad<M>): OptionT2v<M> {
+  const applicativeComposition = getApplicativeComposition(M, option)
+
+  return {
+    ...applicativeComposition,
+    chain: (fa, f) => M.chain(fa, o => (o.isNone() ? M.of(optionNone) : f(o.value)))
+  }
+}
+
+/** @deprecated */
 export interface OptionT<M> extends ApplicativeComposition<M, URI> {
   readonly chain: <A, B>(f: (a: A) => HKT<M, Option<B>>, fa: HKT<M, Option<A>>) => HKT<M, Option<B>>
 }
 
+/** @deprecated */
 export interface OptionT1<M extends URIS> extends ApplicativeComposition11<M, URI> {
   readonly chain: <A, B>(f: (a: A) => Type<M, Option<B>>, fa: Type<M, Option<A>>) => Type<M, Option<B>>
 }
 
+/** @deprecated */
 export interface OptionT2<M extends URIS2> extends ApplicativeComposition21<M, URI> {
   readonly chain: <L, A, B>(f: (a: A) => Type2<M, L, Option<B>>, fa: Type2<M, L, Option<A>>) => Type2<M, L, Option<B>>
 }
 
+/** @deprecated */
 export interface OptionT2C<M extends URIS2, L> extends ApplicativeComposition2C1<M, URI, L> {
   readonly chain: <A, B>(f: (a: A) => Type2<M, L, Option<B>>, fa: Type2<M, L, Option<A>>) => Type2<M, L, Option<B>>
 }
 
+/** @deprecated */
 export interface OptionT3C<M extends URIS3, U, L> extends ApplicativeComposition3C1<M, URI, U, L> {
   readonly chain: <A, B>(
     f: (a: A) => Type3<M, U, L, Option<B>>,
@@ -40,120 +105,155 @@ export interface OptionT3C<M extends URIS3, U, L> extends ApplicativeComposition
 }
 
 /**
+ * Use {@link getOptionT2v} instead
  * @since 1.0.0
+ * @deprecated
  */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS3, U, L>(F: Monad3C<F, U, L>): OptionT3C<F, U, L>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS2>(F: Monad2<F>): OptionT2<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS2, L>(F: Monad2C<F, L>): OptionT2C<F, L>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F extends URIS>(F: Monad1<F>): OptionT1<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F>(F: Monad<F>): OptionT<F>['chain']
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function chain<F>(F: Monad<F>): OptionT<F>['chain'] {
   return (f, fa) => F.chain(fa, o => (o.isNone() ? F.of(optionNone) : f(o.value)))
 }
 
 /**
+ * Use {@link getOptionT2v} instead
  * @since 1.0.0
+ * @deprecated
+ */
+// tslint:disable-next-line: deprecation
+export function getOptionT<M extends URIS3, U, L>(M: Monad3C<M, U, L>): OptionT3C<M, U, L>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getOptionT<M extends URIS2>(M: Monad2<M>): OptionT2<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getOptionT<M extends URIS2, L>(M: Monad2C<M, L>): OptionT2C<M, L>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getOptionT<M extends URIS>(M: Monad1<M>): OptionT1<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getOptionT<M>(M: Monad<M>): OptionT<M>
+// tslint:disable-next-line: deprecation
+export function getOptionT<M>(M: Monad<M>): OptionT<M> {
+  const applicativeComposition = getApplicativeComposition(M, option)
+
+  return {
+    ...applicativeComposition,
+    // tslint:disable-next-line: deprecation
+    chain: chain(M)
+  }
+}
+
+/**
+ * @since 1.0.0
+ * @deprecated
  */
 export function some<F extends URIS3, U, L>(F: Applicative3C<F, U, L>): <A>(a: A) => Type3<F, U, L, Option<A>>
+/** @deprecated */
 export function some<F extends URIS2>(F: Applicative2<F>): <L, A>(a: A) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function some<F extends URIS2, L>(F: Applicative2C<F, L>): <A>(a: A) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function some<F extends URIS>(F: Applicative1<F>): <A>(a: A) => Type<F, Option<A>>
+/** @deprecated */
 export function some<F>(F: Applicative<F>): <A>(a: A) => HKT<F, Option<A>>
+/** @deprecated */
 export function some<F>(F: Applicative<F>): <A>(a: A) => HKT<F, Option<A>> {
   return a => F.of(optionSome(a))
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function none<F extends URIS3, U, L>(F: Applicative3C<F, U, L>): () => Type3<F, U, L, Option<never>>
+/** @deprecated */
 export function none<F extends URIS2>(F: Applicative2<F>): <L>() => Type2<F, L, Option<never>>
+/** @deprecated */
 export function none<F extends URIS2, L>(F: Applicative2C<F, L>): () => Type2<F, L, Option<never>>
+/** @deprecated */
 export function none<F extends URIS>(F: Applicative1<F>): () => Type<F, Option<never>>
+/** @deprecated */
 export function none<F>(F: Applicative<F>): () => HKT<F, Option<never>>
+/** @deprecated */
 export function none<F>(F: Applicative<F>): () => HKT<F, Option<never>> {
   return () => F.of(optionNone)
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function fromOption<F extends URIS3, U, L>(
   F: Applicative3C<F, U, L>
 ): <A>(fa: Option<A>) => Type3<F, U, L, Option<A>>
 export function fromOption<F extends URIS2>(F: Applicative2<F>): <L, A>(fa: Option<A>) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function fromOption<F extends URIS2, L>(F: Applicative2C<F, L>): <A>(fa: Option<A>) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function fromOption<F extends URIS>(F: Applicative1<F>): <A>(fa: Option<A>) => Type<F, Option<A>>
+/** @deprecated */
 export function fromOption<F>(F: Applicative<F>): <A>(fa: Option<A>) => HKT<F, Option<A>>
+/** @deprecated */
 export function fromOption<F>(F: Applicative<F>): <A>(fa: Option<A>) => HKT<F, Option<A>> {
-  return oa => F.of(oa)
+  return F.of
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function liftF<F extends URIS3, U, L>(
   F: Functor3C<F, U, L>
 ): <A>(fa: Type3<F, U, L, A>) => Type3<F, U, L, Option<A>>
+/** @deprecated */
 export function liftF<F extends URIS2>(F: Functor2<F>): <L, A>(fa: Type2<F, L, A>) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function liftF<F extends URIS2, L>(F: Functor2C<F, L>): <A>(fa: Type2<F, L, A>) => Type2<F, L, Option<A>>
+/** @deprecated */
 export function liftF<F extends URIS>(F: Functor1<F>): <A>(fa: Type<F, A>) => Type<F, Option<A>>
+/** @deprecated */
 export function liftF<F>(F: Functor<F>): <A>(fa: HKT<F, A>) => HKT<F, Option<A>>
+/** @deprecated */
 export function liftF<F>(F: Functor<F>): <A>(fa: HKT<F, A>) => HKT<F, Option<A>> {
-  return fa => F.map(fa, a => optionSome(a))
-}
-
-/**
- * @since 1.0.0
- */
-export function fold<F extends URIS3, U, L>(
-  F: Functor3C<F, U, L>
-): <R, A>(r: R, some: (a: A) => R, fa: Type3<F, U, L, Option<A>>) => Type3<F, U, L, R>
-export function fold<F extends URIS2>(
-  F: Functor2<F>
-): <L, R, A>(r: R, some: (a: A) => R, fa: Type2<F, L, Option<A>>) => Type2<F, L, R>
-export function fold<F extends URIS2, L>(
-  F: Functor2C<F, L>
-): <R, A>(r: R, some: (a: A) => R, fa: Type2<F, L, Option<A>>) => Type2<F, L, R>
-export function fold<F extends URIS>(
-  F: Functor1<F>
-): <R, A>(r: R, some: (a: A) => R, fa: Type<F, Option<A>>) => Type<F, R>
-export function fold<F>(F: Functor<F>): <R, A>(r: R, some: (a: A) => R, fa: HKT<F, Option<A>>) => HKT<F, R>
-export function fold<F>(F: Functor<F>): <R, A>(r: R, some: (a: A) => R, fa: HKT<F, Option<A>>) => HKT<F, R> {
-  return (r, some, fa) => F.map(fa, o => (o.isNone() ? r : some(o.value)))
+  return fa => F.map(fa, optionSome)
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function getOrElse<F extends URIS3, U, L>(
   F: Functor3C<F, U, L>
 ): <A>(a: A) => (fa: Type3<F, U, L, Option<A>>) => Type3<F, U, L, A>
+/** @deprecated */
 export function getOrElse<F extends URIS2>(
   F: Functor2<F>
 ): <A>(a: A) => <L>(fa: Type2<F, L, Option<A>>) => Type2<F, L, A>
+/** @deprecated */
 export function getOrElse<F extends URIS2, L>(
   F: Functor2C<F, L>
 ): <A>(a: A) => (fa: Type2<F, L, Option<A>>) => Type2<F, L, A>
+/** @deprecated */
 export function getOrElse<F extends URIS>(F: Functor1<F>): <A>(a: A) => (fa: Type<F, Option<A>>) => Type<F, A>
+/** @deprecated */
 export function getOrElse<F>(F: Functor<F>): <A>(a: A) => (fa: HKT<F, Option<A>>) => HKT<F, A>
+/** @deprecated */
 export function getOrElse<F>(F: Functor<F>): <A>(a: A) => (fa: HKT<F, Option<A>>) => HKT<F, A> {
   return a => fa => F.map(fa, o => o.getOrElse(a))
 }
-
-/**
- * @since 1.0.0
- */
-export function getOptionT<M extends URIS3, U, L>(M: Monad3C<M, U, L>): OptionT3C<M, U, L>
-export function getOptionT<M extends URIS2>(M: Monad2<M>): OptionT2<M>
-export function getOptionT<M extends URIS2, L>(M: Monad2C<M, L>): OptionT2C<M, L>
-export function getOptionT<M extends URIS>(M: Monad1<M>): OptionT1<M>
-export function getOptionT<M>(M: Monad<M>): OptionT<M>
-export function getOptionT<M>(M: Monad<M>): OptionT<M> {
-  const applicativeComposition = getApplicativeComposition(M, option)
-
-  return {
-    ...applicativeComposition,
-    chain: chain(M)
-  }
-}
diff --git a/src/ReaderT.ts b/src/ReaderT.ts
index d3659c94..490b9c9e 100644
--- a/src/ReaderT.ts
+++ b/src/ReaderT.ts
@@ -5,6 +5,76 @@ import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 import { Monad, Monad1, Monad2, Monad3 } from './Monad'
 import { Reader } from './Reader'
 
+export interface ReaderT2v<M> {
+  readonly map: <E, A, B>(fa: (e: E) => HKT<M, A>, f: (a: A) => B) => (e: E) => HKT<M, B>
+  readonly of: <E, A>(a: A) => (e: E) => HKT<M, A>
+  readonly ap: <E, A, B>(fab: (e: E) => HKT<M, (a: A) => B>, fa: (e: E) => HKT<M, A>) => (e: E) => HKT<M, B>
+  readonly chain: <E, A, B>(fa: (e: E) => HKT<M, A>, f: (a: A) => (e: E) => HKT<M, B>) => (e: E) => HKT<M, B>
+}
+
+export interface ReaderT2v1<M extends URIS> {
+  readonly map: <E, A, B>(fa: (e: E) => Type<M, A>, f: (a: A) => B) => (e: E) => Type<M, B>
+  readonly of: <E, A>(a: A) => (e: E) => Type<M, A>
+  readonly ap: <E, A, B>(fab: (e: E) => Type<M, (a: A) => B>, fa: (e: E) => Type<M, A>) => (e: E) => Type<M, B>
+  readonly chain: <E, A, B>(fa: (e: E) => Type<M, A>, f: (a: A) => (e: E) => Type<M, B>) => (e: E) => Type<M, B>
+}
+
+export interface ReaderT2v2<M extends URIS2> {
+  readonly map: <L, E, A, B>(fa: (e: E) => Type2<M, L, A>, f: (a: A) => B) => (e: E) => Type2<M, L, B>
+  readonly of: <L, E, A>(a: A) => (e: E) => Type2<M, L, A>
+  readonly ap: <L, E, A, B>(
+    fab: (e: E) => Type2<M, L, (a: A) => B>,
+    fa: (e: E) => Type2<M, L, A>
+  ) => (e: E) => Type2<M, L, B>
+  readonly chain: <L, E, A, B>(
+    fa: (e: E) => Type2<M, L, A>,
+    f: (a: A) => (e: E) => Type2<M, L, B>
+  ) => (e: E) => Type2<M, L, B>
+}
+
+export interface ReaderT2v3<M extends URIS3> {
+  readonly map: <U, L, E, A, B>(fa: (e: E) => Type3<M, U, L, A>, f: (a: A) => B) => (e: E) => Type3<M, U, L, B>
+  readonly of: <U, L, E, A>(a: A) => (e: E) => Type3<M, U, L, A>
+  readonly ap: <U, L, E, A, B>(
+    fab: (e: E) => Type3<M, U, L, (a: A) => B>,
+    fa: (e: E) => Type3<M, U, L, A>
+  ) => (e: E) => Type3<M, U, L, B>
+  readonly chain: <U, L, E, A, B>(
+    fa: (e: E) => Type3<M, U, L, A>,
+    f: (a: A) => (e: E) => Type3<M, U, L, B>
+  ) => (e: E) => Type3<M, U, L, B>
+}
+
+/**
+ * @since 1.2.0
+ */
+export function fromReader<F extends URIS3>(
+  F: Applicative3<F>
+): <E, U, L, A>(fa: Reader<E, A>) => (e: E) => Type3<F, U, L, A>
+export function fromReader<F extends URIS2>(F: Applicative2<F>): <E, L, A>(fa: Reader<E, A>) => (e: E) => Type2<F, L, A>
+export function fromReader<F extends URIS>(F: Applicative1<F>): <E, A>(fa: Reader<E, A>) => (e: E) => Type<F, A>
+export function fromReader<F>(F: Applicative<F>): <E, A>(fa: Reader<E, A>) => (e: E) => HKT<F, A>
+export function fromReader<F>(F: Applicative<F>): <E, A>(fa: Reader<E, A>) => (e: E) => HKT<F, A> {
+  return fa => e => F.of(fa.run(e))
+}
+
+/**
+ * @since 1.14.0
+ */
+export function getReaderT2v<M extends URIS3>(M: Monad3<M>): ReaderT2v3<M>
+export function getReaderT2v<M extends URIS2>(M: Monad2<M>): ReaderT2v2<M>
+export function getReaderT2v<M extends URIS>(M: Monad1<M>): ReaderT2v1<M>
+export function getReaderT2v<M>(M: Monad<M>): ReaderT2v<M>
+export function getReaderT2v<M>(M: Monad<M>): ReaderT2v<M> {
+  return {
+    map: (fa, f) => e => M.map(fa(e), f),
+    of: a => () => M.of(a),
+    ap: (fab, fa) => e => M.ap(fab(e), fa(e)),
+    chain: (fa, f) => e => M.chain(fa(e), a => f(a)(e))
+  }
+}
+
+/** @deprecated */
 export interface ReaderT<M> {
   readonly map: <E, A, B>(f: (a: A) => B, fa: (e: E) => HKT<M, A>) => (e: E) => HKT<M, B>
   readonly of: <E, A>(a: A) => (e: E) => HKT<M, A>
@@ -12,6 +82,7 @@ export interface ReaderT<M> {
   readonly chain: <E, A, B>(f: (a: A) => (e: E) => HKT<M, B>, fa: (e: E) => HKT<M, A>) => (e: E) => HKT<M, B>
 }
 
+/** @deprecated */
 export interface ReaderT1<M extends URIS> {
   readonly map: <E, A, B>(f: (a: A) => B, fa: (e: E) => Type<M, A>) => (e: E) => Type<M, B>
   readonly of: <E, A>(a: A) => (e: E) => Type<M, A>
@@ -19,6 +90,7 @@ export interface ReaderT1<M extends URIS> {
   readonly chain: <E, A, B>(f: (a: A) => (e: E) => Type<M, B>, fa: (e: E) => Type<M, A>) => (e: E) => Type<M, B>
 }
 
+/** @deprecated */
 export interface ReaderT2<M extends URIS2> {
   readonly map: <L, E, A, B>(f: (a: A) => B, fa: (e: E) => Type2<M, L, A>) => (e: E) => Type2<M, L, B>
   readonly of: <L, E, A>(a: A) => (e: E) => Type2<M, L, A>
@@ -32,6 +104,7 @@ export interface ReaderT2<M extends URIS2> {
   ) => (e: E) => Type2<M, L, B>
 }
 
+/** @deprecated */
 export interface ReaderT3<M extends URIS3> {
   readonly map: <U, L, E, A, B>(f: (a: A) => B, fa: (e: E) => Type3<M, U, L, A>) => (e: E) => Type3<M, U, L, B>
   readonly of: <U, L, E, A>(a: A) => (e: E) => Type3<M, U, L, A>
@@ -46,35 +119,108 @@ export interface ReaderT3<M extends URIS3> {
 }
 
 /**
+ * Use {@link map2v} instead
  * @since 1.0.0
+ * @deprecated
  */
 export function map<F extends URIS3>(
   F: Functor3<F>
 ): <U, L, E, A, B>(f: (a: A) => B, fa: (e: E) => Type3<F, U, L, A>) => (e: E) => Type3<F, U, L, B>
+/** @deprecated */
 export function map<F extends URIS2>(
   F: Functor2<F>
 ): <L, E, A, B>(f: (a: A) => B, fa: (e: E) => Type2<F, L, A>) => (e: E) => Type2<F, L, B>
+/** @deprecated */
 export function map<F extends URIS>(
   F: Functor1<F>
 ): <E, A, B>(f: (a: A) => B, fa: (e: E) => Type<F, A>) => (e: E) => Type<F, B>
+/** @deprecated */
 export function map<F>(F: Functor<F>): <E, A, B>(f: (a: A) => B, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B>
+/** @deprecated */
 export function map<F>(F: Functor<F>): <E, A, B>(f: (a: A) => B, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B> {
   return (f, fa) => e => F.map(fa(e), f)
 }
 
 /**
+ * Use {@link getReaderT2v} instead
+ * @since 1.0.0
+ * @deprecated
+ */
+export function chain<F extends URIS3>(
+  F: Chain3<F>
+): <U, L, E, A, B>(
+  f: (a: A) => (e: E) => Type3<F, U, L, B>,
+  fa: (e: E) => Type3<F, U, L, A>
+) => (e: E) => Type3<F, U, L, B>
+/** @deprecated */
+export function chain<F extends URIS2>(
+  F: Chain2<F>
+): <L, E, A, B>(f: (a: A) => (e: E) => Type2<F, L, B>, fa: (e: E) => Type2<F, L, A>) => (e: E) => Type2<F, L, B>
+/** @deprecated */
+export function chain<F extends URIS>(
+  F: Chain1<F>
+): <E, A, B>(f: (a: A) => (e: E) => Type<F, B>, fa: (e: E) => Type<F, A>) => (e: E) => Type<F, B>
+/** @deprecated */
+export function chain<F>(
+  F: Chain<F>
+): <E, A, B>(f: (a: A) => (e: E) => HKT<F, B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B>
+/** @deprecated */
+export function chain<F>(
+  F: Chain<F>
+): <E, A, B>(f: (a: A) => (e: E) => HKT<F, B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B> {
+  return (f, fa) => e => F.chain(fa(e), a => f(a)(e))
+}
+
+/**
+ * Use {@link getReaderT2v} instead
  * @since 1.0.0
+ * @deprecated
+ */
+// tslint:disable-next-line: deprecation
+export function getReaderT<M extends URIS3>(M: Monad3<M>): ReaderT3<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getReaderT<M extends URIS2>(M: Monad2<M>): ReaderT2<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getReaderT<M extends URIS>(M: Monad1<M>): ReaderT1<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getReaderT<M>(M: Monad<M>): ReaderT<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
+export function getReaderT<M>(M: Monad<M>): ReaderT<M> {
+  return {
+    // tslint:disable-next-line: deprecation
+    map: map(M),
+    // tslint:disable-next-line: deprecation
+    of: of(M),
+    // tslint:disable-next-line: deprecation
+    ap: ap(M),
+    // tslint:disable-next-line: deprecation
+    chain: chain(M)
+  }
+}
+
+/**
+ * @since 1.0.0
+ * @deprecated
  */
 export function of<F extends URIS3>(F: Applicative3<F>): <U, L, E, A>(a: A) => (e: E) => Type3<F, U, L, A>
+/** @deprecated */
 export function of<F extends URIS2>(F: Applicative2<F>): <L, E, A>(a: A) => (e: E) => Type2<F, L, A>
+/** @deprecated */
 export function of<F extends URIS>(F: Applicative1<F>): <E, A>(a: A) => (e: E) => Type<F, A>
+/** @deprecated */
 export function of<F>(F: Applicative<F>): <E, A>(a: A) => (e: E) => HKT<F, A>
+/** @deprecated */
 export function of<F>(F: Applicative<F>): <E, A>(a: A) => (e: E) => HKT<F, A> {
   return <A>(a: A) => () => F.of(a)
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function ap<F extends URIS3>(
   F: Applicative3<F>
@@ -82,15 +228,19 @@ export function ap<F extends URIS3>(
   fab: (e: E) => Type3<F, U, L, (a: A) => B>,
   fa: (e: E) => Type3<F, U, L, A>
 ) => (e: E) => Type3<F, U, L, B>
+/** @deprecated */
 export function ap<F extends URIS2>(
   F: Applicative2<F>
 ): <L, E, A, B>(fab: (e: E) => Type2<F, L, (a: A) => B>, fa: (e: E) => Type2<F, L, A>) => (e: E) => Type2<F, L, B>
+/** @deprecated */
 export function ap<F extends URIS>(
   F: Applicative1<F>
 ): <E, A, B>(fab: (e: E) => Type<F, (a: A) => B>, fa: (e: E) => Type<F, A>) => (e: E) => Type<F, B>
+/** @deprecated */
 export function ap<F>(
   F: Applicative<F>
 ): <E, A, B>(fab: (e: E) => HKT<F, (a: A) => B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B>
+/** @deprecated */
 export function ap<F>(
   F: Applicative<F>
 ): <E, A, B>(fab: (e: E) => HKT<F, (a: A) => B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B> {
@@ -99,75 +249,32 @@ export function ap<F>(
 
 /**
  * @since 1.0.0
- */
-export function chain<F extends URIS3>(
-  F: Chain3<F>
-): <U, L, E, A, B>(
-  f: (a: A) => (e: E) => Type3<F, U, L, B>,
-  fa: (e: E) => Type3<F, U, L, A>
-) => (e: E) => Type3<F, U, L, B>
-export function chain<F extends URIS2>(
-  F: Chain2<F>
-): <L, E, A, B>(f: (a: A) => (e: E) => Type2<F, L, B>, fa: (e: E) => Type2<F, L, A>) => (e: E) => Type2<F, L, B>
-export function chain<F extends URIS>(
-  F: Chain1<F>
-): <E, A, B>(f: (a: A) => (e: E) => Type<F, B>, fa: (e: E) => Type<F, A>) => (e: E) => Type<F, B>
-export function chain<F>(
-  F: Chain<F>
-): <E, A, B>(f: (a: A) => (e: E) => HKT<F, B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B>
-export function chain<F>(
-  F: Chain<F>
-): <E, A, B>(f: (a: A) => (e: E) => HKT<F, B>, fa: (e: E) => HKT<F, A>) => (e: E) => HKT<F, B> {
-  return (f, fa) => e => F.chain(fa(e), a => f(a)(e))
-}
-
-/**
- * @since 1.0.0
+ * @deprecated
  */
 export function ask<F extends URIS3>(F: Applicative3<F>): <U, L, E>() => (e: E) => Type3<F, U, L, E>
+/** @deprecated */
 export function ask<F extends URIS2>(F: Applicative2<F>): <L, E>() => (e: E) => Type2<F, L, E>
+/** @deprecated */
 export function ask<F extends URIS>(F: Applicative1<F>): <E>() => (e: E) => Type<F, E>
+/** @deprecated */
 export function ask<F>(F: Applicative<F>): <E>() => (e: E) => HKT<F, E>
+/** @deprecated */
 export function ask<F>(F: Applicative<F>): <E>() => (e: E) => HKT<F, E> {
   return () => F.of
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function asks<F extends URIS3>(F: Applicative3<F>): <U, L, E, A>(f: (e: E) => A) => (e: E) => Type3<F, U, L, A>
+/** @deprecated */
 export function asks<F extends URIS2>(F: Applicative2<F>): <L, E, A>(f: (e: E) => A) => (e: E) => Type2<F, L, A>
+/** @deprecated */
 export function asks<F extends URIS>(F: Applicative1<F>): <E, A>(f: (e: E) => A) => (e: E) => Type<F, A>
+/** @deprecated */
 export function asks<F>(F: Applicative<F>): <E, A>(f: (e: E) => A) => (e: E) => HKT<F, A>
+/** @deprecated */
 export function asks<F>(F: Applicative<F>): <E, A>(f: (e: E) => A) => (e: E) => HKT<F, A> {
   return f => e => F.of(f(e))
 }
-
-/**
- * @since 1.2.0
- */
-export function fromReader<F extends URIS3>(
-  F: Applicative3<F>
-): <E, U, L, A>(fa: Reader<E, A>) => (e: E) => Type3<F, U, L, A>
-export function fromReader<F extends URIS2>(F: Applicative2<F>): <E, L, A>(fa: Reader<E, A>) => (e: E) => Type2<F, L, A>
-export function fromReader<F extends URIS>(F: Applicative1<F>): <E, A>(fa: Reader<E, A>) => (e: E) => Type<F, A>
-export function fromReader<F>(F: Applicative<F>): <E, A>(fa: Reader<E, A>) => (e: E) => HKT<F, A>
-export function fromReader<F>(F: Applicative<F>): <E, A>(fa: Reader<E, A>) => (e: E) => HKT<F, A> {
-  return fa => e => F.of(fa.run(e))
-}
-
-/**
- * @since 1.0.0
- */
-export function getReaderT<M extends URIS3>(M: Monad3<M>): ReaderT3<M>
-export function getReaderT<M extends URIS2>(M: Monad2<M>): ReaderT2<M>
-export function getReaderT<M extends URIS>(M: Monad1<M>): ReaderT1<M>
-export function getReaderT<M>(M: Monad<M>): ReaderT<M>
-export function getReaderT<M>(M: Monad<M>): ReaderT<M> {
-  return {
-    map: map(M),
-    of: of(M),
-    ap: ap(M),
-    chain: chain(M)
-  }
-}
diff --git a/src/ReaderTaskEither.ts b/src/ReaderTaskEither.ts
index 523e3d96..084e4422 100644
--- a/src/ReaderTaskEither.ts
+++ b/src/ReaderTaskEither.ts
@@ -13,7 +13,7 @@ import * as taskEither from './TaskEither'
 import TaskEither = taskEither.TaskEither
 import { MonadTask3 } from './MonadTask'
 
-const readerTTaskEither = readerT.getReaderT(taskEither.taskEither)
+const readerTTaskEither = readerT.getReaderT2v(taskEither.taskEither)
 
 declare module './HKT' {
   interface URI2HKT3<U, L, A> {
@@ -41,7 +41,7 @@ export class ReaderTaskEither<E, L, A> {
     return this.value(e).run()
   }
   map<B>(f: (a: A) => B): ReaderTaskEither<E, L, B> {
-    return new ReaderTaskEither(readerTTaskEither.map(f, this.value))
+    return new ReaderTaskEither(readerTTaskEither.map(this.value, f))
   }
   ap<B>(fab: ReaderTaskEither<E, L, (a: A) => B>): ReaderTaskEither<E, L, B> {
     return new ReaderTaskEither(readerTTaskEither.ap(fab.value, this.value))
@@ -65,7 +65,7 @@ export class ReaderTaskEither<E, L, A> {
     return fb.ap(this.map(constIdentity as () => (b: B) => B))
   }
   chain<B>(f: (a: A) => ReaderTaskEither<E, L, B>): ReaderTaskEither<E, L, B> {
-    return new ReaderTaskEither(readerTTaskEither.chain(a => f(a).value, this.value))
+    return new ReaderTaskEither(readerTTaskEither.chain(this.value, a => f(a).value))
   }
   fold<R>(left: (l: L) => R, right: (a: A) => R): Reader<E, Task<R>> {
     return new Reader(e => this.value(e).fold(left, right))
@@ -127,20 +127,18 @@ const bimap = <E, L, V, A, B>(
   return fa.bimap(f, g)
 }
 
-const readerTask = readerT.ask(taskEither.taskEither)
 /**
  * @since 1.6.0
  */
 export const ask = <E, L>(): ReaderTaskEither<E, L, E> => {
-  return new ReaderTaskEither(readerTask())
+  return new ReaderTaskEither(e => taskEither.taskEither.of(e))
 }
 
-const readerTasks = readerT.asks(taskEither.taskEither)
 /**
  * @since 1.6.0
  */
 export const asks = <E, L, A>(f: (e: E) => A): ReaderTaskEither<E, L, A> => {
-  return new ReaderTaskEither(readerTasks(f))
+  return new ReaderTaskEither(e => taskEither.taskEither.of(f(e)))
 }
 
 /**
diff --git a/src/StateT.ts b/src/StateT.ts
index 324f1f6b..8ed4b7d8 100644
--- a/src/StateT.ts
+++ b/src/StateT.ts
@@ -6,6 +6,156 @@ import { Monad, Monad1, Monad2, Monad3 } from './Monad'
 import { State } from './State'
 import { Endomorphism, tuple } from './function'
 
+export interface StateT2v<M> {
+  readonly map: <S, A, B>(fa: (s: S) => HKT<M, [A, S]>, f: (a: A) => B) => (s: S) => HKT<M, [B, S]>
+  readonly of: <S, A>(a: A) => (s: S) => HKT<M, [A, S]>
+  readonly ap: <S, A, B>(
+    fab: (s: S) => HKT<M, [(a: A) => B, S]>,
+    fa: (s: S) => HKT<M, [A, S]>
+  ) => (s: S) => HKT<M, [B, S]>
+  readonly chain: <S, A, B>(
+    fa: (s: S) => HKT<M, [A, S]>,
+    f: (a: A) => (s: S) => HKT<M, [B, S]>
+  ) => (s: S) => HKT<M, [B, S]>
+}
+
+export interface StateT2v1<M extends URIS> {
+  readonly map: <S, A, B>(fa: (s: S) => Type<M, [A, S]>, f: (a: A) => B) => (s: S) => Type<M, [B, S]>
+  readonly of: <S, A>(a: A) => (s: S) => Type<M, [A, S]>
+  readonly ap: <S, A, B>(
+    fab: (s: S) => Type<M, [(a: A) => B, S]>,
+    fa: (s: S) => Type<M, [A, S]>
+  ) => (s: S) => Type<M, [B, S]>
+  readonly chain: <S, A, B>(
+    fa: (s: S) => Type<M, [A, S]>,
+    f: (a: A) => (s: S) => Type<M, [B, S]>
+  ) => (s: S) => Type<M, [B, S]>
+}
+
+export interface StateT2v2<M extends URIS2> {
+  readonly map: <L, S, A, B>(fa: (s: S) => Type2<M, L, [A, S]>, f: (a: A) => B) => (s: S) => Type2<M, L, [B, S]>
+  readonly of: <L, S, A>(a: A) => (s: S) => Type2<M, L, [A, S]>
+  readonly ap: <L, S, A, B>(
+    fab: (s: S) => Type2<M, L, [(a: A) => B, S]>,
+    fa: (s: S) => Type2<M, L, [A, S]>
+  ) => (s: S) => Type2<M, L, [B, S]>
+  readonly chain: <L, S, A, B>(
+    fa: (s: S) => Type2<M, L, [A, S]>,
+    f: (a: A) => (s: S) => Type2<M, L, [B, S]>
+  ) => (s: S) => Type2<M, L, [B, S]>
+}
+
+export interface StateT2v3<M extends URIS3> {
+  readonly map: <U, L, S, A, B>(
+    fa: (s: S) => Type3<M, U, L, [A, S]>,
+    f: (a: A) => B
+  ) => (s: S) => Type3<M, U, L, [B, S]>
+  readonly of: <U, L, S, A>(a: A) => (s: S) => Type3<M, U, L, [A, S]>
+  readonly ap: <U, L, S, A, B>(
+    fab: (s: S) => Type3<M, U, L, [(a: A) => B, S]>,
+    fa: (s: S) => Type3<M, U, L, [A, S]>
+  ) => (s: S) => Type3<M, U, L, [B, S]>
+  readonly chain: <U, L, S, A, B>(
+    fa: (s: S) => Type3<M, U, L, [A, S]>,
+    f: (a: A) => (s: S) => Type3<M, U, L, [B, S]>
+  ) => (s: S) => Type3<M, U, L, [B, S]>
+}
+
+/**
+ * @since 1.14.0
+ */
+export function get2v<F extends URIS3>(F: Applicative3<F>): <S, U, L>(s: S) => Type3<F, U, L, [S, S]>
+export function get2v<F extends URIS2>(F: Applicative2<F>): <S, L>(s: S) => Type2<F, L, [S, S]>
+export function get2v<F extends URIS>(F: Applicative1<F>): <S>(s: S) => Type<F, [S, S]>
+export function get2v<F>(F: Applicative<F>): <S>(s: S) => HKT<F, [S, S]>
+export function get2v<F>(F: Applicative<F>): <S>(s: S) => HKT<F, [S, S]> {
+  return s => F.of(tuple(s, s))
+}
+
+/**
+ * @since 1.0.0
+ */
+export function put<F extends URIS3>(F: Applicative3<F>): <S>(s: S) => <U, L>() => Type3<F, U, L, [void, S]>
+export function put<F extends URIS2>(F: Applicative2<F>): <S>(s: S) => <L>() => Type2<F, L, [void, S]>
+export function put<F extends URIS>(F: Applicative1<F>): <S>(s: S) => () => Type<F, [void, S]>
+export function put<F>(F: Applicative<F>): <S>(s: S) => () => HKT<F, [void, S]>
+export function put<F>(F: Applicative<F>): <S>(s: S) => () => HKT<F, [void, S]> {
+  return s => () => F.of(tuple(undefined, s))
+}
+
+/**
+ * @since 1.0.0
+ */
+export function modify<F extends URIS3>(
+  F: Applicative3<F>
+): <S>(f: Endomorphism<S>) => <U, L>(s: S) => Type3<F, U, L, [void, S]>
+export function modify<F extends URIS2>(
+  F: Applicative2<F>
+): <S>(f: Endomorphism<S>) => <L>(s: S) => Type2<F, L, [void, S]>
+export function modify<F extends URIS>(F: Applicative1<F>): <S>(f: Endomorphism<S>) => (s: S) => Type<F, [void, S]>
+export function modify<F>(F: Applicative<F>): <S>(f: Endomorphism<S>) => (s: S) => HKT<F, [void, S]>
+export function modify<F>(F: Applicative<F>): <S>(f: Endomorphism<S>) => (s: S) => HKT<F, [void, S]> {
+  return f => s => F.of(tuple(undefined, f(s)))
+}
+
+/**
+ * @since 1.0.0
+ */
+export function gets<F extends URIS3>(
+  F: Applicative3<F>
+): <S, A>(f: (s: S) => A) => <U, L>(s: S) => Type3<F, U, L, [A, S]>
+export function gets<F extends URIS2>(F: Applicative2<F>): <S, A>(f: (s: S) => A) => <L>(s: S) => Type2<F, L, [A, S]>
+export function gets<F extends URIS>(F: Applicative1<F>): <S, A>(f: (s: S) => A) => (s: S) => Type<F, [A, S]>
+export function gets<F>(F: Applicative<F>): <S, A>(f: (s: S) => A) => (s: S) => HKT<F, [A, S]>
+export function gets<F>(F: Applicative<F>): <S, A>(f: (s: S) => A) => (s: S) => HKT<F, [A, S]> {
+  return f => s => F.of(tuple(f(s), s))
+}
+
+/**
+ * @since 1.2.0
+ */
+export function fromState<F extends URIS3>(
+  F: Applicative3<F>
+): <S, A, U, L>(fa: State<S, A>) => (s: S) => Type3<F, U, L, [A, S]>
+export function fromState<F extends URIS2>(
+  F: Applicative2<F>
+): <S, A, L>(fa: State<S, A>) => (s: S) => Type2<F, L, [A, S]>
+export function fromState<F extends URIS>(F: Applicative1<F>): <S, A>(fa: State<S, A>) => (s: S) => Type<F, [A, S]>
+export function fromState<F>(F: Applicative<F>): <S, A>(fa: State<S, A>) => (s: S) => HKT<F, [A, S]>
+export function fromState<F>(F: Applicative<F>): <S, A>(fa: State<S, A>) => (s: S) => HKT<F, [A, S]> {
+  return fa => s => F.of(fa.run(s))
+}
+
+/**
+ * @since 1.2.0
+ */
+export function liftF<F extends URIS3>(
+  F: Functor3<F>
+): <U, L, S, A>(fa: Type3<F, U, L, A>) => (s: S) => Type3<F, U, L, [A, S]>
+export function liftF<F extends URIS2>(F: Functor2<F>): <L, S, A>(fa: Type2<F, L, A>) => (s: S) => Type2<F, L, [A, S]>
+export function liftF<F extends URIS>(F: Functor1<F>): <S, A>(fa: Type<F, A>) => (s: S) => Type<F, [A, S]>
+export function liftF<F>(F: Functor<F>): <S, A>(fa: HKT<F, A>) => (s: S) => HKT<F, [A, S]>
+export function liftF<F>(F: Functor<F>): <S, A>(fa: HKT<F, A>) => (s: S) => HKT<F, [A, S]> {
+  return fa => s => F.map(fa, a => tuple(a, s))
+}
+
+/**
+ * @since 1.14.0
+ */
+export function getStateT2v<M extends URIS3>(M: Monad3<M>): StateT2v3<M>
+export function getStateT2v<M extends URIS2>(M: Monad2<M>): StateT2v2<M>
+export function getStateT2v<M extends URIS>(M: Monad1<M>): StateT2v1<M>
+export function getStateT2v<M>(M: Monad<M>): StateT2v<M>
+export function getStateT2v<M>(M: Monad<M>): StateT2v<M> {
+  return {
+    map: (fa, f) => s => M.map(fa(s), ([a, s1]) => tuple(f(a), s1)),
+    of: a => s => M.of(tuple(a, s)),
+    ap: (fab, fa) => s => M.chain(fab(s), ([f, s]) => M.map(fa(s), ([a, s]) => tuple(f(a), s))),
+    chain: (fa, f) => s => M.chain(fa(s), ([a, s1]) => f(a)(s1))
+  }
+}
+
+/** @deprecated */
 export interface StateT<M> {
   readonly map: <S, A, B>(f: (a: A) => B, fa: (s: S) => HKT<M, [A, S]>) => (s: S) => HKT<M, [B, S]>
   readonly of: <S, A>(a: A) => (s: S) => HKT<M, [A, S]>
@@ -19,6 +169,7 @@ export interface StateT<M> {
   ) => (s: S) => HKT<M, [B, S]>
 }
 
+/** @deprecated */
 export interface StateT1<M extends URIS> {
   readonly map: <S, A, B>(f: (a: A) => B, fa: (s: S) => Type<M, [A, S]>) => (s: S) => Type<M, [B, S]>
   readonly of: <S, A>(a: A) => (s: S) => Type<M, [A, S]>
@@ -32,6 +183,7 @@ export interface StateT1<M extends URIS> {
   ) => (s: S) => Type<M, [B, S]>
 }
 
+/** @deprecated */
 export interface StateT2<M extends URIS2> {
   readonly map: <L, S, A, B>(f: (a: A) => B, fa: (s: S) => Type2<M, L, [A, S]>) => (s: S) => Type2<M, L, [B, S]>
   readonly of: <L, S, A>(a: A) => (s: S) => Type2<M, L, [A, S]>
@@ -45,6 +197,7 @@ export interface StateT2<M extends URIS2> {
   ) => (s: S) => Type2<M, L, [B, S]>
 }
 
+/** @deprecated */
 export interface StateT3<M extends URIS3> {
   readonly map: <U, L, S, A, B>(
     f: (a: A) => B,
@@ -63,19 +216,24 @@ export interface StateT3<M extends URIS3> {
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function map<F extends URIS3>(
   F: Functor3<F>
 ): <U, L, S, A, B>(f: (a: A) => B, fa: (s: S) => Type3<F, U, L, [A, S]>) => (s: S) => Type3<F, U, L, [B, S]>
+/** @deprecated */
 export function map<F extends URIS2>(
   F: Functor2<F>
 ): <L, S, A, B>(f: (a: A) => B, fa: (s: S) => Type2<F, L, [A, S]>) => (s: S) => Type2<F, L, [B, S]>
+/** @deprecated */
 export function map<F extends URIS>(
   F: Functor1<F>
 ): <S, A, B>(f: (a: A) => B, fa: (s: S) => Type<F, [A, S]>) => (s: S) => Type<F, [B, S]>
+/** @deprecated */
 export function map<F>(
   F: Functor<F>
 ): <S, A, B>(f: (a: A) => B, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]>
+/** @deprecated */
 export function map<F>(
   F: Functor<F>
 ): <S, A, B>(f: (a: A) => B, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]> {
@@ -84,17 +242,7 @@ export function map<F>(
 
 /**
  * @since 1.0.0
- */
-export function of<F extends URIS3>(F: Applicative3<F>): <U, L, S, A>(a: A) => (s: S) => Type3<F, U, L, [A, S]>
-export function of<F extends URIS2>(F: Applicative2<F>): <L, S, A>(a: A) => (s: S) => Type2<F, L, [A, S]>
-export function of<F extends URIS>(F: Applicative1<F>): <S, A>(a: A) => (s: S) => Type<F, [A, S]>
-export function of<F>(F: Applicative<F>): <S, A>(a: A) => (s: S) => HKT<F, [A, S]>
-export function of<F>(F: Applicative<F>): <S, A>(a: A) => (s: S) => HKT<F, [A, S]> {
-  return a => s => F.of(tuple(a, s))
-}
-
-/**
- * @since 1.0.0
+ * @deprecated
  */
 export function ap<F extends URIS3>(
   F: Chain3<F>
@@ -102,28 +250,31 @@ export function ap<F extends URIS3>(
   fab: (s: S) => Type3<F, U, L, [(a: A) => B, S]>,
   fa: (s: S) => Type3<F, U, L, [A, S]>
 ) => (s: S) => Type3<F, U, L, [B, S]>
+/** @deprecated */
 export function ap<F extends URIS2>(
   F: Chain2<F>
 ): <L, S, A, B>(
   fab: (s: S) => Type2<F, L, [(a: A) => B, S]>,
   fa: (s: S) => Type2<F, L, [A, S]>
 ) => (s: S) => Type2<F, L, [B, S]>
+/** @deprecated */
 export function ap<F extends URIS>(
   F: Chain1<F>
 ): <S, A, B>(fab: (s: S) => Type<F, [(a: A) => B, S]>, fa: (s: S) => Type<F, [A, S]>) => (s: S) => Type<F, [B, S]>
+/** @deprecated */
 export function ap<F>(
   F: Chain<F>
 ): <S, A, B>(fab: (s: S) => HKT<F, [(a: A) => B, S]>, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]>
+/** @deprecated */
 export function ap<F>(
   F: Chain<F>
 ): <S, A, B>(fab: (s: S) => HKT<F, [(a: A) => B, S]>, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]> {
-  const mapF = map(F)
-  const chainF = chain(F)
-  return (fab, fa) => chainF(f => mapF(f, fa), fab) // <- derived
+  return (fab, fa) => s => F.chain(fab(s), ([f, s]) => F.map(fa(s), ([a, s]) => tuple(f(a), s)))
 }
 
 /**
  * @since 1.0.0
+ * @deprecated
  */
 export function chain<F extends URIS3>(
   F: Chain3<F>
@@ -131,18 +282,22 @@ export function chain<F extends URIS3>(
   f: (a: A) => (s: S) => Type3<F, U, L, [B, S]>,
   fa: (s: S) => Type3<F, U, L, [A, S]>
 ) => (s: S) => Type3<F, U, L, [B, S]>
+/** @deprecated */
 export function chain<F extends URIS2>(
   F: Chain2<F>
 ): <L, S, A, B>(
   f: (a: A) => (s: S) => Type2<F, L, [B, S]>,
   fa: (s: S) => Type2<F, L, [A, S]>
 ) => (s: S) => Type2<F, L, [B, S]>
+/** @deprecated */
 export function chain<F extends URIS>(
   F: Chain1<F>
 ): <S, A, B>(f: (a: A) => (s: S) => Type<F, [B, S]>, fa: (s: S) => Type<F, [A, S]>) => (s: S) => Type<F, [B, S]>
+/** @deprecated */
 export function chain<F>(
   F: Chain<F>
 ): <S, A, B>(f: (a: A) => (s: S) => HKT<F, [B, S]>, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]>
+/** @deprecated */
 export function chain<F>(
   F: Chain<F>
 ): <S, A, B>(f: (a: A) => (s: S) => HKT<F, [B, S]>, fa: (s: S) => HKT<F, [A, S]>) => (s: S) => HKT<F, [B, S]> {
@@ -150,95 +305,64 @@ export function chain<F>(
 }
 
 /**
+ * Use {@link getStateT2v} instead
  * @since 1.0.0
+ * @deprecated
  */
-export function get<F extends URIS3>(F: Applicative3<F>): <S>() => <U, L>(s: S) => Type3<F, U, L, [S, S]>
-export function get<F extends URIS2>(F: Applicative2<F>): <S>() => <L>(s: S) => Type2<F, L, [S, S]>
-export function get<F extends URIS>(F: Applicative1<F>): <S>() => (s: S) => Type<F, [S, S]>
-export function get<F>(F: Applicative<F>): <S>() => (s: S) => HKT<F, [S, S]>
-export function get<F>(F: Applicative<F>): <S>() => (s: S) => HKT<F, [S, S]> {
-  return () => s => F.of(tuple(s, s))
-}
-
-/**
- * @since 1.0.0
- */
-export function put<F extends URIS3>(F: Applicative3<F>): <S>(s: S) => <U, L>() => Type3<F, U, L, [void, S]>
-export function put<F extends URIS2>(F: Applicative2<F>): <S>(s: S) => <L>() => Type2<F, L, [void, S]>
-export function put<F extends URIS>(F: Applicative1<F>): <S>(s: S) => () => Type<F, [void, S]>
-export function put<F>(F: Applicative<F>): <S>(s: S) => () => HKT<F, [void, S]>
-export function put<F>(F: Applicative<F>): <S>(s: S) => () => HKT<F, [void, S]> {
-  return s => () => F.of(tuple(undefined, s))
-}
-
-/**
- * @since 1.0.0
- */
-export function modify<F extends URIS3>(
-  F: Applicative3<F>
-): <S>(f: Endomorphism<S>) => <U, L>(s: S) => Type3<F, U, L, [void, S]>
-export function modify<F extends URIS2>(
-  F: Applicative2<F>
-): <S>(f: Endomorphism<S>) => <L>(s: S) => Type2<F, L, [void, S]>
-export function modify<F extends URIS>(F: Applicative1<F>): <S>(f: Endomorphism<S>) => (s: S) => Type<F, [void, S]>
-export function modify<F>(F: Applicative<F>): <S>(f: Endomorphism<S>) => (s: S) => HKT<F, [void, S]>
-export function modify<F>(F: Applicative<F>): <S>(f: Endomorphism<S>) => (s: S) => HKT<F, [void, S]> {
-  return f => s => F.of(tuple(undefined, f(s)))
-}
-
-/**
- * @since 1.0.0
- */
-export function gets<F extends URIS3>(
-  F: Applicative3<F>
-): <S, A>(f: (s: S) => A) => <U, L>(s: S) => Type3<F, U, L, [A, S]>
-export function gets<F extends URIS2>(F: Applicative2<F>): <S, A>(f: (s: S) => A) => <L>(s: S) => Type2<F, L, [A, S]>
-export function gets<F extends URIS>(F: Applicative1<F>): <S, A>(f: (s: S) => A) => (s: S) => Type<F, [A, S]>
-export function gets<F>(F: Applicative<F>): <S, A>(f: (s: S) => A) => (s: S) => HKT<F, [A, S]>
-export function gets<F>(F: Applicative<F>): <S, A>(f: (s: S) => A) => (s: S) => HKT<F, [A, S]> {
-  return f => s => F.of(tuple(f(s), s))
-}
-
-/**
- * @since 1.2.0
- */
-export function fromState<F extends URIS3>(
-  F: Applicative3<F>
-): <S, A, U, L>(fa: State<S, A>) => (s: S) => Type3<F, U, L, [A, S]>
-export function fromState<F extends URIS2>(
-  F: Applicative2<F>
-): <S, A, L>(fa: State<S, A>) => (s: S) => Type2<F, L, [A, S]>
-export function fromState<F extends URIS>(F: Applicative1<F>): <S, A>(fa: State<S, A>) => (s: S) => Type<F, [A, S]>
-export function fromState<F>(F: Applicative<F>): <S, A>(fa: State<S, A>) => (s: S) => HKT<F, [A, S]>
-export function fromState<F>(F: Applicative<F>): <S, A>(fa: State<S, A>) => (s: S) => HKT<F, [A, S]> {
-  return fa => s => F.of(fa.run(s))
-}
-
-/**
- * @since 1.2.0
- */
-export function liftF<F extends URIS3>(
-  F: Functor3<F>
-): <U, L, S, A>(fa: Type3<F, U, L, A>) => (s: S) => Type3<F, U, L, [A, S]>
-export function liftF<F extends URIS2>(F: Functor2<F>): <L, S, A>(fa: Type2<F, L, A>) => (s: S) => Type2<F, L, [A, S]>
-export function liftF<F extends URIS>(F: Functor1<F>): <S, A>(fa: Type<F, A>) => (s: S) => Type<F, [A, S]>
-export function liftF<F>(F: Functor<F>): <S, A>(fa: HKT<F, A>) => (s: S) => HKT<F, [A, S]>
-export function liftF<F>(F: Functor<F>): <S, A>(fa: HKT<F, A>) => (s: S) => HKT<F, [A, S]> {
-  return fa => s => F.map(fa, a => tuple(a, s))
-}
-
-/**
- * @since 1.0.0
- */
+// tslint:disable-next-line: deprecation
 export function getStateT<M extends URIS3>(M: Monad3<M>): StateT3<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function getStateT<M extends URIS2>(M: Monad2<M>): StateT2<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function getStateT<M extends URIS>(M: Monad1<M>): StateT1<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function getStateT<M>(M: Monad<M>): StateT<M>
+/** @deprecated */
+// tslint:disable-next-line: deprecation
 export function getStateT<M>(M: Monad<M>): StateT<M> {
   return {
+    // tslint:disable-next-line: deprecation
     map: map(M),
+    // tslint:disable-next-line: deprecation
     of: of(M),
+    // tslint:disable-next-line: deprecation
     ap: ap(M),
+    // tslint:disable-next-line: deprecation
     chain: chain(M)
   }
 }
+
+/**
+ * @since 1.0.0
+ * @deprecated
+ */
+export function of<F extends URIS3>(F: Applicative3<F>): <U, L, S, A>(a: A) => (s: S) => Type3<F, U, L, [A, S]>
+/** @deprecated */
+export function of<F extends URIS2>(F: Applicative2<F>): <L, S, A>(a: A) => (s: S) => Type2<F, L, [A, S]>
+/** @deprecated */
+export function of<F extends URIS>(F: Applicative1<F>): <S, A>(a: A) => (s: S) => Type<F, [A, S]>
+/** @deprecated */
+export function of<F>(F: Applicative<F>): <S, A>(a: A) => (s: S) => HKT<F, [A, S]>
+/** @deprecated */
+export function of<F>(F: Applicative<F>): <S, A>(a: A) => (s: S) => HKT<F, [A, S]> {
+  return a => s => F.of(tuple(a, s))
+}
+
+/**
+ * @since 1.0.0
+ * @deprecated
+ */
+export function get<F extends URIS3>(F: Applicative3<F>): <S>() => <U, L>(s: S) => Type3<F, U, L, [S, S]>
+/** @deprecated */
+export function get<F extends URIS2>(F: Applicative2<F>): <S>() => <L>(s: S) => Type2<F, L, [S, S]>
+/** @deprecated */
+export function get<F extends URIS>(F: Applicative1<F>): <S>() => (s: S) => Type<F, [S, S]>
+/** @deprecated */
+export function get<F>(F: Applicative<F>): <S>() => (s: S) => HKT<F, [S, S]>
+/** @deprecated */
+export function get<F>(F: Applicative<F>): <S>() => (s: S) => HKT<F, [S, S]> {
+  return () => s => F.of(tuple(s, s))
+}
diff --git a/src/StrMap.ts b/src/StrMap.ts
index 1160b9bb..1fbc2efc 100644
--- a/src/StrMap.ts
+++ b/src/StrMap.ts
@@ -230,8 +230,9 @@ const foldrWithIndex = <A, B>(fa: StrMap<A>, b: B, f: (k: string, a: A, b: B) =>
 }
 
 /**
- *
+ * Use {@link strmap.traverseWithIndex}
  * @since 1.0.0
+ * @deprecated
  */
 export function traverseWithKey<F extends URIS3>(
   F: Applicative3<F>
@@ -446,6 +447,7 @@ const mapWithIndex = <A, B>(fa: StrMap<A>, f: (i: string, a: A) => B): StrMap<B>
   return fa.mapWithKey(f)
 }
 
+// tslint:disable-next-line: deprecation
 const traverseWithIndex = traverseWithKey
 
 const partitionMapWithIndex = <RL, RR, A>(
diff --git a/src/TaskEither.ts b/src/TaskEither.ts
index 080c41f6..fcd4972c 100644
--- a/src/TaskEither.ts
+++ b/src/TaskEither.ts
@@ -25,15 +25,12 @@ declare module './HKT' {
   }
 }
 
-const eitherTTask = eitherT.getEitherT(task)
-
 export const URI = 'TaskEither'
 
 export type URI = typeof URI
 
-const eitherTfold = eitherT.fold(task)
-const eitherTmapLeft = eitherT.mapLeft(task)
-const eitherTbimap = eitherT.bimap(task)
+const T = eitherT.getEitherT2v(task)
+const foldT = eitherT.fold(task)
 
 /**
  * `TaskEither<L, A>` represents an asynchronous computation that either yields a value of type `A` or fails yielding an
@@ -52,10 +49,10 @@ export class TaskEither<L, A> {
     return this.value.run()
   }
   map<B>(f: (a: A) => B): TaskEither<L, B> {
-    return new TaskEither(eitherTTask.map(this.value, f))
+    return new TaskEither(T.map(this.value, f))
   }
   ap<B>(fab: TaskEither<L, (a: A) => B>): TaskEither<L, B> {
-    return new TaskEither(eitherTTask.ap(fab.value, this.value))
+    return new TaskEither(T.ap(fab.value, this.value))
   }
   /**
    * Flipped version of {@link ap}
@@ -92,10 +89,10 @@ export class TaskEither<L, A> {
     return this.chain(() => fb)
   }
   chain<B>(f: (a: A) => TaskEither<L, B>): TaskEither<L, B> {
-    return new TaskEither(eitherTTask.chain(a => f(a).value, this.value))
+    return new TaskEither(T.chain(this.value, a => f(a).value))
   }
   fold<R>(onLeft: (l: L) => R, onRight: (a: A) => R): Task<R> {
-    return eitherTfold(onLeft, onRight, this.value)
+    return foldT(onLeft, onRight, this.value)
   }
   /**
    * Similar to {@link fold}, but the result is flattened.
@@ -112,13 +109,13 @@ export class TaskEither<L, A> {
     return new TaskEither(this.value.chain(e => e.fold(onLeft, onRight).value))
   }
   mapLeft<M>(f: (l: L) => M): TaskEither<M, A> {
-    return new TaskEither(eitherTmapLeft(f)(this.value))
+    return new TaskEither(this.value.map(e => e.mapLeft(f)))
   }
   /**
    * Transforms the failure value of the `TaskEither` into a new `TaskEither`
    */
   orElse<M>(f: (l: L) => TaskEither<M, A>): TaskEither<M, A> {
-    return new TaskEither(this.value.chain(e => e.fold<Task<Either<M, A>>>(l => f(l).value, eitherTTask.of)))
+    return new TaskEither(this.value.chain(e => e.fold<Task<Either<M, A>>>(l => f(l).value, T.of)))
   }
   /**
    * @since 1.6.0
@@ -130,7 +127,7 @@ export class TaskEither<L, A> {
    * @since 1.2.0
    */
   bimap<V, B>(f: (l: L) => V, g: (a: A) => B): TaskEither<V, B> {
-    return new TaskEither(eitherTbimap(this.value, f, g))
+    return new TaskEither(this.value.map(e => e.bimap(f, g)))
   }
   /**
    * Return `Right` if the given action succeeds, `Left` if it throws
@@ -162,7 +159,7 @@ const map = <L, A, B>(fa: TaskEither<L, A>, f: (a: A) => B): TaskEither<L, B> =>
 }
 
 const of = <L, A>(a: A): TaskEither<L, A> => {
-  return new TaskEither(eitherTTask.of(a))
+  return new TaskEither(T.of(a))
 }
 
 const ap = <L, A, B>(fab: TaskEither<L, (a: A) => B>, fa: TaskEither<L, A>): TaskEither<L, B> => {
@@ -181,28 +178,25 @@ const bimap = <L, V, A, B>(fa: TaskEither<L, A>, f: (l: L) => V, g: (a: A) => B)
   return fa.bimap(f, g)
 }
 
-const eitherTright = eitherT.right(task)
 /**
  * @since 1.0.0
  */
 export const right = <L, A>(fa: Task<A>): TaskEither<L, A> => {
-  return new TaskEither(eitherTright(fa))
+  return new TaskEither(fa.map(a => eitherRight(a)))
 }
 
-const eitherTleft = eitherT.left(task)
 /**
  * @since 1.0.0
  */
-export const left = <L, A>(fa: Task<L>): TaskEither<L, A> => {
-  return new TaskEither(eitherTleft(fa))
+export const left = <L, A>(fl: Task<L>): TaskEither<L, A> => {
+  return new TaskEither(fl.map(l => eitherLeft(l)))
 }
 
-const eitherTfromEither = eitherT.fromEither(task)
 /**
  * @since 1.0.0
  */
 export const fromEither = <L, A>(fa: Either<L, A>): TaskEither<L, A> => {
-  return new TaskEither(eitherTfromEither(fa))
+  return new TaskEither(task.of(fa))
 }
 
 /**


Test patch:
diff --git a/test/EitherT.ts b/test/EitherT.ts
index 336ee147..bcca65ff 100644
--- a/test/EitherT.ts
+++ b/test/EitherT.ts
@@ -1,18 +1,72 @@
 import * as assert from 'assert'
 import * as eitherT from '../src/EitherT'
-import * as either from '../src/Either'
+import { left, right } from '../src/Either'
 import { task } from '../src/Task'
+import { option, some, none } from '../src/Option'
 
 describe('EitherT', () => {
-  it('chain', () => {
-    const chain = eitherT.chain(task)
-    const of = eitherT.getEitherT(task).of
+  it('right', () => {
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.right(option)(none), none)
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.right(option)(some(1)), some(right(1)))
+  })
+
+  it('left', () => {
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.left(option)(none), none)
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.left(option)(some(1)), some(left(1)))
+  })
+
+  it('fromEither', () => {
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.fromEither(option)(right(1)), some(right(1)))
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.fromEither(option)(left(1)), some(left(1)))
+  })
+
+  it('mapLeft', () => {
+    const len = (s: string): number => s.length
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.mapLeft(option)(len)(none), none)
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.mapLeft(option)(len)(some(right(1))), some(right(1)))
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.mapLeft(option)(len)(some(left('foo'))), some(left(3)))
+  })
+
+  it('bimap', () => {
+    const len = (s: string): number => s.length
+    const double = (n: number): number => n * 2
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.bimap(option)(none, len, double), none)
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.bimap(option)(some(right<string, number>(1)), len, double), some(right(2)))
+    // tslint:disable-next-line: deprecation
+    assert.deepStrictEqual(eitherT.bimap(option)(some(left<string, number>('foo')), len, double), some(left(3)))
+  })
+
+  it('getEitherT', () => {
+    // tslint:disable-next-line: deprecation
+    const { chain, of } = eitherT.getEitherT(task)
     const f = (n: number) => of(n * 2)
     const x = of(1)
-    const y = eitherT.fromEither(task)<string, number>(either.left('foo'))
+    const y = task.of(left<string, number>('foo'))
     return Promise.all([chain(f, x).run(), chain(f, y).run()]).then(([e1, e2]) => {
-      assert.deepStrictEqual(e1, either.right(2))
-      assert.deepStrictEqual(e2, either.left('foo'))
+      assert.deepStrictEqual(e1, right(2))
+      assert.deepStrictEqual(e2, left('foo'))
+    })
+  })
+
+  it('getEitherT2v', () => {
+    const { chain, of } = eitherT.getEitherT2v(task)
+    const f = (n: number) => of(n * 2)
+    const x = of(1)
+    const y = task.of(left<string, number>('foo'))
+    return Promise.all([chain(x, f).run(), chain(y, f).run()]).then(([e1, e2]) => {
+      assert.deepStrictEqual(e1, right(2))
+      assert.deepStrictEqual(e2, left('foo'))
     })
   })
 })
diff --git a/test/OptionT.ts b/test/OptionT.ts
index c51ab9d0..f2a568ec 100644
--- a/test/OptionT.ts
+++ b/test/OptionT.ts
@@ -3,7 +3,10 @@ import * as option from '../src/Option'
 import * as optionT from '../src/OptionT'
 import { task } from '../src/Task'
 
+// tslint:disable-next-line: deprecation
 const taskOption = optionT.getOptionT(task)
+const taskOption2v = optionT.getOptionT2v(task)
+// tslint:disable-next-line: deprecation
 const none = optionT.none(task)()
 
 describe('OptionT', () => {
@@ -24,6 +27,15 @@ describe('OptionT', () => {
     })
   })
 
+  it('getOptionT2v', () => {
+    const to1 = taskOption2v.chain(taskOption2v.of('foo'), a => taskOption2v.of(a.length))
+    const to2 = taskOption2v.chain(none, (a: string) => taskOption2v.of(a.length))
+    return Promise.all([to1.run(), to2.run()]).then(([o1, o2]) => {
+      assert.deepStrictEqual(o1, option.some(3))
+      assert.deepStrictEqual(o2, option.none)
+    })
+  })
+
   it('fold', () => {
     const f = 'none'
     const g = (s: string) => `some${s.length}`
@@ -44,6 +56,7 @@ describe('OptionT', () => {
 
   it('getOrElse', () => {
     const greetingT = taskOption.of('welcome')
+    // tslint:disable-next-line: deprecation
     const getOrElse = optionT.getOrElse(task)('hello, there!')
     const p1 = getOrElse(greetingT)
       .run()
@@ -59,6 +72,7 @@ describe('OptionT', () => {
   })
 
   it('some', () => {
+    // tslint:disable-next-line: deprecation
     const some = optionT.some(task)
     return some(1)
       .run()
@@ -68,6 +82,7 @@ describe('OptionT', () => {
   })
 
   it('fromOption', () => {
+    // tslint:disable-next-line: deprecation
     const fromOption = optionT.fromOption(task)
     return Promise.all([fromOption(option.some(1)).run(), fromOption(option.none).run()]).then(([o1, o2]) => {
       assert.deepStrictEqual(o1, option.some(1))
@@ -76,6 +91,7 @@ describe('OptionT', () => {
   })
 
   it('liftF', () => {
+    // tslint:disable-next-line: deprecation
     const liftF = optionT.liftF(task)
     return liftF(task.of(1))
       .run()
diff --git a/test/ReaderT.ts b/test/ReaderT.ts
index 6a1727d9..0f50c4aa 100644
--- a/test/ReaderT.ts
+++ b/test/ReaderT.ts
@@ -4,15 +4,16 @@ import { reader } from '../src/Reader'
 import * as readerT from '../src/ReaderT'
 import { StrMap, lookup } from '../src/StrMap'
 
-const readerOption = readerT.getReaderT(option)
-
 describe('ReaderT', () => {
   it('fromReader', () => {
     const f = readerT.fromReader(option)(reader.of<void, number>(1))
     assert.deepStrictEqual(f(undefined), some(1))
   })
 
-  it('ReaderOption', () => {
+  it('getReaderT', () => {
+    // tslint:disable-next-line: deprecation
+    const readerOption = readerT.getReaderT(option)
+
     function configure(key: string) {
       return (e: StrMap<string>) => lookup(key, e)
     }
@@ -39,13 +40,45 @@ describe('ReaderT', () => {
     assert.deepStrictEqual(setupConnection(badConfig), none)
   })
 
+  it('getReaderT2v', () => {
+    const readerOption = readerT.getReaderT2v(option)
+
+    function configure(key: string) {
+      return (e: StrMap<string>) => lookup(key, e)
+    }
+
+    const setupConnection = readerOption.chain(configure('host'), host => {
+      return readerOption.chain(configure('user'), user => {
+        return readerOption.map(configure('password'), password => [host, user, password] as [string, string, string])
+      })
+    })
+
+    const goodConfig = new StrMap({
+      host: 'myhost',
+      user: 'giulio',
+      password: 'password'
+    })
+
+    assert.deepStrictEqual(setupConnection(goodConfig), some(['myhost', 'giulio', 'password']))
+
+    const badConfig = new StrMap({
+      host: 'myhost',
+      user: 'giulio'
+    })
+
+    assert.deepStrictEqual(setupConnection(badConfig), none)
+  })
+
   it('of', () => {
+    // tslint:disable-next-line: deprecation
     const of = readerT.of(option)
     assert.deepStrictEqual(of(1)({}), some(1))
   })
 
   it('ap', () => {
+    // tslint:disable-next-line: deprecation
     const of = readerT.of(option)
+    // tslint:disable-next-line: deprecation
     const ap = readerT.ap(option)
     const double = (n: number): number => n * 2
     const fab = of(double)
@@ -54,11 +87,13 @@ describe('ReaderT', () => {
   })
 
   it('ask', () => {
+    // tslint:disable-next-line: deprecation
     const ask = readerT.ask(option)
     assert.deepStrictEqual(ask()(1), some(1))
   })
 
   it('asks', () => {
+    // tslint:disable-next-line: deprecation
     const asks = readerT.asks(option)
     assert.deepStrictEqual(asks((s: string) => s.length)('foo'), some(3))
   })
diff --git a/test/StateT.ts b/test/StateT.ts
index ca1c5aaf..9e3d6fd6 100644
--- a/test/StateT.ts
+++ b/test/StateT.ts
@@ -3,7 +3,8 @@ import * as option from '../src/Option'
 import { state } from '../src/State'
 import * as stateT from '../src/StateT'
 
-const stateTOption = stateT.getStateT(option.option)
+// tslint:disable-next-line: deprecation
+const T = stateT.getStateT(option.option)
 
 describe('StateT', () => {
   it('put', () => {
@@ -11,9 +12,14 @@ describe('StateT', () => {
   })
 
   it('get', () => {
+    // tslint:disable-next-line: deprecation
     assert.deepStrictEqual(stateT.get(option.option)()(1), option.some([1, 1]))
   })
 
+  it('get2v', () => {
+    assert.deepStrictEqual(stateT.get2v(option.option)(1), option.some([1, 1]))
+  })
+
   it('modify', () => {
     const double = (n: number) => n * 2
     assert.deepStrictEqual(stateT.modify(option.option)(double)(1), option.some([undefined, 2]))
@@ -27,25 +33,48 @@ describe('StateT', () => {
   it('map', () => {
     const double = (n: number) => n * 2
     const state = (s: number) => option.some<[number, number]>([s - 1, s + 1])
-    assert.deepStrictEqual(stateTOption.map(double, state)(0), option.some([-2, 1]))
+    assert.deepStrictEqual(T.map(double, state)(0), option.some([-2, 1]))
+  })
+
+  it('getStateT2v', () => {
+    const stateTOption2v = stateT.getStateT2v(option.option)
+
+    // map
+    const double = (n: number) => n * 2
+    const s1 = (s: number) => option.some<[number, number]>([s - 1, s + 1])
+    assert.deepStrictEqual(stateTOption2v.map(s1, double)(0), option.some([-2, 1]))
+
+    // aof
+    const x = stateTOption2v.of(1)
+    assert.deepStrictEqual(x(0), option.some([1, 0]))
+
+    // ap
+    const fab = stateTOption2v.of(double)
+    const fa = stateTOption2v.of(1)
+    assert.deepStrictEqual(stateTOption2v.ap(fab, fa)(0), option.some([2, 0]))
+
+    // chain
+    const f = (_n: number) => (s: number) => option.some<[number, number]>([s - 1, s + 1])
+    const s2 = (s: number) => option.some<[number, number]>([s - 1, s + 1])
+    assert.deepStrictEqual(stateTOption2v.chain(s2, f)(0), option.some([0, 2]))
   })
 
   it('of', () => {
-    const x = stateTOption.of(1)
+    const x = T.of(1)
     assert.deepStrictEqual(x(0), option.some([1, 0]))
   })
 
   it('ap', () => {
     const double = (n: number) => n * 2
-    const fab = stateTOption.of(double)
-    const fa = stateTOption.of(1)
-    assert.deepStrictEqual(stateTOption.ap(fab, fa)(0), option.some([2, 0]))
+    const fab = T.of(double)
+    const fa = T.of(1)
+    assert.deepStrictEqual(T.ap(fab, fa)(0), option.some([2, 0]))
   })
 
   it('chain', () => {
     const f = (_n: number) => (s: number) => option.some<[number, number]>([s - 1, s + 1])
     const state = (s: number) => option.some<[number, number]>([s - 1, s + 1])
-    assert.deepStrictEqual(stateTOption.chain(f, state)(0), option.some([0, 2]))
+    assert.deepStrictEqual(T.chain(f, state)(0), option.some([0, 2]))
   })
 
   it('fromState', () => {