Repository: gcanti/fp-ts
Pull request #781 (2019-03-18 18:50:58)

New Feature: make Apply.sequenceT variadic using mapped types, closes…
… #766

@mattiamanzati thanks a lot for the trick you suggested, deleting all those overloads feels so good


Patch:
diff --git a/README.md b/README.md
index ae249c3b..8f760aaa 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 <h3 align="center">
   <a href="https://gcanti.github.io/fp-ts/">
-    <img src="fp-ts-logo.png">
+    <img src="./docs/fp-ts-logo.png">
   </a>
 </h3>
 
@@ -36,6 +36,7 @@ A distinctive feature of `fp-ts` with respect to other functional libraries is i
 
 <!-- START doctoc generated TOC please keep comment here to allow auto update -->
 <!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
+
 **Table of contents**
 
 - [Installation](#installation)
@@ -67,12 +68,12 @@ The stable version is tested against **TypeScript 3.3.3**, but should run with T
 
 - [Docs](https://gcanti.github.io/fp-ts)
 - [Tutorial](https://gcanti.github.io/fp-ts/basics/)
-- [Ecosystem](https://gcanti.github.io/fp-ts/introduction/ecosystem/)
+- [Ecosystem](https://gcanti.github.io/fp-ts/introduction/ecosystem)
 - [API Reference](https://gcanti.github.io/fp-ts/modules/)
 
 # Development
 
-- [Code conventions](https://github.com/gcanti/fp-ts/introduction/code-conventions)
+- [Code conventions](https://gcanti.github.io/fp-ts/introduction/code-conventions)
 
 # License
 
diff --git a/docs/modules/Monoid.ts.md b/docs/modules/Monoid.ts.md
index c53b451b..5e9c0c88 100644
--- a/docs/modules/Monoid.ts.md
+++ b/docs/modules/Monoid.ts.md
@@ -246,10 +246,26 @@ Added in v1.14.0
 
 # getTupleMonoid (function)
 
+Given a tuple of monoids returns a monoid for the tuple
+
 **Signature**
 
 ```ts
-export const getTupleMonoid = <A, B>(MA: Monoid<A>, MB: Monoid<B>): Monoid<[A, B]> => ...
+export const getTupleMonoid = <T extends Array<Monoid<any>>>(
+  ...monoids: T
+): Monoid<{ [K in keyof T]: T[K] extends Semigroup<infer A> ? A : never }> => ...
+```
+
+**Example**
+
+```ts
+import { getTupleMonoid, monoidString, monoidSum, monoidAll } from 'fp-ts/lib/Monoid'
+
+const M1 = getTupleMonoid(monoidString, monoidSum)
+assert.deepStrictEqual(M1.concat(['a', 1], ['b', 2]), ['ab', 3])
+
+const M2 = getTupleMonoid(monoidString, monoidSum, monoidAll)
+assert.deepStrictEqual(M2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
 ```
 
 Added in v1.0.0
diff --git a/docs/modules/NonEmptyArray.ts.md b/docs/modules/NonEmptyArray.ts.md
index 493501f9..bbe5b04b 100644
--- a/docs/modules/NonEmptyArray.ts.md
+++ b/docs/modules/NonEmptyArray.ts.md
@@ -475,6 +475,8 @@ Added in v1.14.0
 
 ## ~~index~~ (method)
 
+Use `lookup` instead
+
 **Signature**
 
 ```ts
@@ -490,7 +492,7 @@ Find the first element which satisfies a predicate (or a refinement) function
 **Signature**
 
 ```ts
-findFirst<B extends A>(predicate: Refinement<A, B>): Option<B>
+findFirst<B extends A>(refinement: Refinement<A, B>): Option<B>
 findFirst(predicate: Predicate<A>): Option<A> { ... }
 ```
 
@@ -683,7 +685,6 @@ export const URI = ...
 ```ts
 export const nonEmptyArray: Monad1<URI> &
   Comonad1<URI> &
-  Foldable2v1<URI> &
   TraversableWithIndex1<URI, number> &
   FunctorWithIndex1<URI, number> &
   FoldableWithIndex1<URI, number> = ...
@@ -693,7 +694,7 @@ Added in v1.0.0
 
 # fromArray (function)
 
-Builds `NonEmptyArray` from `Array` returning `Option.none` or `Option.some` depending on amount of values in passed array
+Builds a `NonEmptyArray` from an `Array` returning `none` if `as` is an empty array
 
 **Signature**
 
@@ -705,7 +706,7 @@ Added in v1.0.0
 
 # getSemigroup (function)
 
-Builds `Semigroup` instance for `NonEmptyArray` of specified type arument
+Builds a `Semigroup` instance for `NonEmptyArray`
 
 **Signature**
 
diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md
index e8a4b38e..efaed823 100644
--- a/docs/modules/Option.ts.md
+++ b/docs/modules/Option.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Option.ts
-nav_order: 60
+nav_order: 61
 parent: Modules
 ---
 
diff --git a/docs/modules/OptionT.ts.md b/docs/modules/OptionT.ts.md
index b0d896b5..5543c2ee 100644
--- a/docs/modules/OptionT.ts.md
+++ b/docs/modules/OptionT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: OptionT.ts
-nav_order: 61
+nav_order: 62
 parent: Modules
 ---
 
diff --git a/docs/modules/Ord.ts.md b/docs/modules/Ord.ts.md
index dd8da039..2fbf4a09 100644
--- a/docs/modules/Ord.ts.md
+++ b/docs/modules/Ord.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ord.ts
-nav_order: 62
+nav_order: 63
 parent: Modules
 ---
 
@@ -173,10 +173,25 @@ Added in v1.0.0
 
 # getTupleOrd (function)
 
+Given a tuple of `Ord`s returns an `Ord` for the tuple
+
 **Signature**
 
 ```ts
-export const getTupleOrd = <A, B>(OA: Ord<A>, OB: Ord<B>): Ord<[A, B]> => ...
+export const getTupleOrd = <T extends Array<Ord<any>>>(
+  ...ords: T
+): Ord<{ [K in keyof T]: T[K] extends Ord<infer A> ? A : never }> => ...
+```
+
+**Example**
+
+```ts
+import { getTupleOrd, ordString, ordNumber, ordBoolean } from 'fp-ts/lib/Ord'
+
+const O = getTupleOrd(ordString, ordNumber, ordBoolean)
+assert.strictEqual(O.compare(['a', 1, true], ['b', 2, true]), -1)
+assert.strictEqual(O.compare(['a', 1, true], ['a', 2, true]), -1)
+assert.strictEqual(O.compare(['a', 1, true], ['a', 1, false]), 1)
 ```
 
 Added in v1.14.3
diff --git a/docs/modules/Ordering.ts.md b/docs/modules/Ordering.ts.md
index 4642b633..5dbc4dc2 100644
--- a/docs/modules/Ordering.ts.md
+++ b/docs/modules/Ordering.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ordering.ts
-nav_order: 63
+nav_order: 64
 parent: Modules
 ---
 
diff --git a/docs/modules/Pair.ts.md b/docs/modules/Pair.ts.md
index 5ae5270e..c2bc2962 100644
--- a/docs/modules/Pair.ts.md
+++ b/docs/modules/Pair.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Pair.ts
-nav_order: 64
+nav_order: 65
 parent: Modules
 ---
 
diff --git a/docs/modules/Plus.ts.md b/docs/modules/Plus.ts.md
index b71274fa..1297f726 100644
--- a/docs/modules/Plus.ts.md
+++ b/docs/modules/Plus.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Plus.ts
-nav_order: 65
+nav_order: 66
 parent: Modules
 ---
 
diff --git a/docs/modules/Profunctor.ts.md b/docs/modules/Profunctor.ts.md
index 3a1f9520..a94cad73 100644
--- a/docs/modules/Profunctor.ts.md
+++ b/docs/modules/Profunctor.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Profunctor.ts
-nav_order: 66
+nav_order: 67
 parent: Modules
 ---
 
diff --git a/docs/modules/Random.ts.md b/docs/modules/Random.ts.md
index d382331e..15e0de18 100644
--- a/docs/modules/Random.ts.md
+++ b/docs/modules/Random.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Random.ts
-nav_order: 67
+nav_order: 68
 parent: Modules
 ---
 
diff --git a/docs/modules/Reader.ts.md b/docs/modules/Reader.ts.md
index 32d38a11..977290ad 100644
--- a/docs/modules/Reader.ts.md
+++ b/docs/modules/Reader.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Reader.ts
-nav_order: 68
+nav_order: 69
 parent: Modules
 ---
 
diff --git a/docs/modules/ReaderT.ts.md b/docs/modules/ReaderT.ts.md
index 7c804257..a8d32d11 100644
--- a/docs/modules/ReaderT.ts.md
+++ b/docs/modules/ReaderT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ReaderT.ts
-nav_order: 69
+nav_order: 70
 parent: Modules
 ---
 
diff --git a/docs/modules/ReaderTaskEither.ts.md b/docs/modules/ReaderTaskEither.ts.md
index b1bad276..c788b164 100644
--- a/docs/modules/ReaderTaskEither.ts.md
+++ b/docs/modules/ReaderTaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: ReaderTaskEither.ts
-nav_order: 70
+nav_order: 71
 parent: Modules
 ---
 
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index bc9d30d3..356d5e19 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Record.ts
-nav_order: 71
+nav_order: 72
 parent: Modules
 ---
 
diff --git a/docs/modules/Ring.ts.md b/docs/modules/Ring.ts.md
index 81a06230..a58c911b 100644
--- a/docs/modules/Ring.ts.md
+++ b/docs/modules/Ring.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Ring.ts
-nav_order: 72
+nav_order: 73
 parent: Modules
 ---
 
@@ -62,10 +62,28 @@ Added in v1.0.0
 
 # getTupleRing (function)
 
+Given a tuple of `Ring`s returns a `Ring` for the tuple
+
 **Signature**
 
 ```ts
-export const getTupleRing = <A, B>(RA: Ring<A>, RB: Ring<B>): Ring<[A, B]> => ...
+export const getTupleRing = <T extends Array<Ring<any>>>(
+  ...rings: T
+): Ring<{ [K in keyof T]: T[K] extends Ring<infer A> ? A : never }> => ...
+```
+
+**Example**
+
+```ts
+import { getTupleRing } from 'fp-ts/lib/Ring'
+import { fieldNumber } from 'fp-ts/lib/Field'
+
+const R = getTupleRing(fieldNumber, fieldNumber, fieldNumber)
+assert.deepStrictEqual(R.add([1, 2, 3], [4, 5, 6]), [5, 7, 9])
+assert.deepStrictEqual(R.mul([1, 2, 3], [4, 5, 6]), [4, 10, 18])
+assert.deepStrictEqual(R.one, [1, 1, 1])
+assert.deepStrictEqual(R.sub([1, 2, 3], [4, 5, 6]), [-3, -3, -3])
+assert.deepStrictEqual(R.zero, [0, 0, 0])
 ```
 
 Added in v1.14.3
diff --git a/docs/modules/Semigroup.ts.md b/docs/modules/Semigroup.ts.md
index 4d79af48..8f4b3283 100644
--- a/docs/modules/Semigroup.ts.md
+++ b/docs/modules/Semigroup.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semigroup.ts
-nav_order: 73
+nav_order: 74
 parent: Modules
 ---
 
@@ -277,10 +277,26 @@ Added in v1.14.0
 
 # getTupleSemigroup (function)
 
+Given a tuple of semigroups returns a semigroup for the tuple
+
 **Signature**
 
 ```ts
-export const getTupleSemigroup = <A, B>(SA: Semigroup<A>, SB: Semigroup<B>): Semigroup<[A, B]> => ...
+export const getTupleSemigroup = <T extends Array<Semigroup<any>>>(
+  ...semigroups: T
+): Semigroup<{ [K in keyof T]: T[K] extends Semigroup<infer A> ? A : never }> => ...
+```
+
+**Example**
+
+```ts
+import { getTupleSemigroup, semigroupString, semigroupSum, semigroupAll } from 'fp-ts/lib/Semigroup'
+
+const S1 = getTupleSemigroup(semigroupString, semigroupSum)
+assert.deepStrictEqual(S1.concat(['a', 1], ['b', 2]), ['ab', 3])
+
+const S2 = getTupleSemigroup(semigroupString, semigroupSum, semigroupAll)
+assert.deepStrictEqual(S2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
 ```
 
 Added in v1.14.0
diff --git a/docs/modules/Semigroupoid.ts.md b/docs/modules/Semigroupoid.ts.md
index d2b218a4..d408ade4 100644
--- a/docs/modules/Semigroupoid.ts.md
+++ b/docs/modules/Semigroupoid.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semigroupoid.ts
-nav_order: 74
+nav_order: 75
 parent: Modules
 ---
 
diff --git a/docs/modules/Semiring.ts.md b/docs/modules/Semiring.ts.md
index d6222862..9db9cb43 100644
--- a/docs/modules/Semiring.ts.md
+++ b/docs/modules/Semiring.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Semiring.ts
-nav_order: 75
+nav_order: 76
 parent: Modules
 ---
 
diff --git a/docs/modules/Set.ts.md b/docs/modules/Set.ts.md
index 25dc5c81..72358e60 100644
--- a/docs/modules/Set.ts.md
+++ b/docs/modules/Set.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Set.ts
-nav_order: 76
+nav_order: 77
 parent: Modules
 ---
 
diff --git a/docs/modules/Setoid.ts.md b/docs/modules/Setoid.ts.md
index 30f5c82c..b793c404 100644
--- a/docs/modules/Setoid.ts.md
+++ b/docs/modules/Setoid.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Setoid.ts
-nav_order: 77
+nav_order: 78
 parent: Modules
 ---
 
@@ -160,10 +160,26 @@ Added in v1.14.2
 
 # getTupleSetoid (function)
 
+Given a tuple of `Setoid`s returns a `Setoid` for the tuple
+
 **Signature**
 
 ```ts
-export const getTupleSetoid = <A, B>(SA: Setoid<A>, SB: Setoid<B>): Setoid<[A, B]> => ...
+export const getTupleSetoid = <T extends Array<Setoid<any>>>(
+  ...setoids: T
+): Setoid<{ [K in keyof T]: T[K] extends Setoid<infer A> ? A : never }> => ...
+```
+
+**Example**
+
+```ts
+import { getTupleSetoid, setoidString, setoidNumber, setoidBoolean } from 'fp-ts/lib/Setoid'
+
+const S = getTupleSetoid(setoidString, setoidNumber, setoidBoolean)
+assert.strictEqual(S.equals(['a', 1, true], ['a', 1, true]), true)
+assert.strictEqual(S.equals(['a', 1, true], ['b', 1, true]), false)
+assert.strictEqual(S.equals(['a', 1, true], ['a', 2, true]), false)
+assert.strictEqual(S.equals(['a', 1, true], ['a', 1, false]), false)
 ```
 
 Added in v1.14.2
diff --git a/docs/modules/State.ts.md b/docs/modules/State.ts.md
index 7ccbbc93..625e26ff 100644
--- a/docs/modules/State.ts.md
+++ b/docs/modules/State.ts.md
@@ -1,6 +1,6 @@
 ---
 title: State.ts
-nav_order: 78
+nav_order: 79
 parent: Modules
 ---
 
diff --git a/docs/modules/StateT.ts.md b/docs/modules/StateT.ts.md
index 57c7340e..613c5b25 100644
--- a/docs/modules/StateT.ts.md
+++ b/docs/modules/StateT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StateT.ts
-nav_order: 79
+nav_order: 80
 parent: Modules
 ---
 
diff --git a/docs/modules/Store.ts.md b/docs/modules/Store.ts.md
index 3c6ab181..bcda55f5 100644
--- a/docs/modules/Store.ts.md
+++ b/docs/modules/Store.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Store.ts
-nav_order: 80
+nav_order: 81
 parent: Modules
 ---
 
diff --git a/docs/modules/StrMap.ts.md b/docs/modules/StrMap.ts.md
index d530fdec..d44d2cf3 100644
--- a/docs/modules/StrMap.ts.md
+++ b/docs/modules/StrMap.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StrMap.ts
-nav_order: 81
+nav_order: 82
 parent: Modules
 ---
 
diff --git a/docs/modules/Strong.ts.md b/docs/modules/Strong.ts.md
index 051447bf..72095531 100644
--- a/docs/modules/Strong.ts.md
+++ b/docs/modules/Strong.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Strong.ts
-nav_order: 82
+nav_order: 83
 parent: Modules
 ---
 
diff --git a/docs/modules/Task.ts.md b/docs/modules/Task.ts.md
index e569acd8..ae78ad85 100644
--- a/docs/modules/Task.ts.md
+++ b/docs/modules/Task.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Task.ts
-nav_order: 83
+nav_order: 84
 parent: Modules
 ---
 
diff --git a/docs/modules/TaskEither.ts.md b/docs/modules/TaskEither.ts.md
index 17baa4f1..a5e2583f 100644
--- a/docs/modules/TaskEither.ts.md
+++ b/docs/modules/TaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TaskEither.ts
-nav_order: 84
+nav_order: 85
 parent: Modules
 ---
 
diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md
index 25eec201..4c5e0595 100644
--- a/docs/modules/These.ts.md
+++ b/docs/modules/These.ts.md
@@ -1,6 +1,6 @@
 ---
 title: These.ts
-nav_order: 85
+nav_order: 86
 parent: Modules
 ---
 
diff --git a/docs/modules/Trace.ts.md b/docs/modules/Trace.ts.md
index 037d04af..ca86afc2 100644
--- a/docs/modules/Trace.ts.md
+++ b/docs/modules/Trace.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Trace.ts
-nav_order: 86
+nav_order: 87
 parent: Modules
 ---
 
diff --git a/docs/modules/Traversable.ts.md b/docs/modules/Traversable.ts.md
index 9230e06c..b4bc740c 100644
--- a/docs/modules/Traversable.ts.md
+++ b/docs/modules/Traversable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traversable.ts
-nav_order: 87
+nav_order: 88
 parent: Modules
 ---
 
diff --git a/docs/modules/Traversable2v.ts.md b/docs/modules/Traversable2v.ts.md
index 2e780e1a..1bdc1534 100644
--- a/docs/modules/Traversable2v.ts.md
+++ b/docs/modules/Traversable2v.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traversable2v.ts
-nav_order: 88
+nav_order: 89
 parent: Modules
 ---
 
diff --git a/docs/modules/TraversableWithIndex.ts.md b/docs/modules/TraversableWithIndex.ts.md
index 11a382dc..4cf80fb3 100644
--- a/docs/modules/TraversableWithIndex.ts.md
+++ b/docs/modules/TraversableWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TraversableWithIndex.ts
-nav_order: 89
+nav_order: 90
 parent: Modules
 ---
 
diff --git a/docs/modules/Tree.ts.md b/docs/modules/Tree.ts.md
index a9319832..cd25ae3e 100644
--- a/docs/modules/Tree.ts.md
+++ b/docs/modules/Tree.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tree.ts
-nav_order: 90
+nav_order: 91
 parent: Modules
 ---
 
diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md
index b41b1901..d0117d66 100644
--- a/docs/modules/Tuple.ts.md
+++ b/docs/modules/Tuple.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tuple.ts
-nav_order: 91
+nav_order: 92
 parent: Modules
 ---
 
diff --git a/docs/modules/Unfoldable.ts.md b/docs/modules/Unfoldable.ts.md
index abba0286..5c5fc0f0 100644
--- a/docs/modules/Unfoldable.ts.md
+++ b/docs/modules/Unfoldable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Unfoldable.ts
-nav_order: 92
+nav_order: 93
 parent: Modules
 ---
 
diff --git a/docs/modules/Validation.ts.md b/docs/modules/Validation.ts.md
index 3a8ba97c..ff3e0fbe 100644
--- a/docs/modules/Validation.ts.md
+++ b/docs/modules/Validation.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Validation.ts
-nav_order: 93
+nav_order: 94
 parent: Modules
 ---
 
diff --git a/docs/modules/Witherable.ts.md b/docs/modules/Witherable.ts.md
index e2cdabef..661b9515 100644
--- a/docs/modules/Witherable.ts.md
+++ b/docs/modules/Witherable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Witherable.ts
-nav_order: 94
+nav_order: 95
 parent: Modules
 ---
 
diff --git a/docs/modules/Writer.ts.md b/docs/modules/Writer.ts.md
index d9861a4b..6439aebc 100644
--- a/docs/modules/Writer.ts.md
+++ b/docs/modules/Writer.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Writer.ts
-nav_order: 95
+nav_order: 96
 parent: Modules
 ---
 
diff --git a/docs/modules/Zipper.ts.md b/docs/modules/Zipper.ts.md
index f9e286c5..5cb5104d 100644
--- a/docs/modules/Zipper.ts.md
+++ b/docs/modules/Zipper.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Zipper.ts
-nav_order: 96
+nav_order: 97
 parent: Modules
 ---
 
diff --git a/docs/modules/function.ts.md b/docs/modules/function.ts.md
index 9258e1b3..7a39af1f 100644
--- a/docs/modules/function.ts.md
+++ b/docs/modules/function.ts.md
@@ -644,7 +644,7 @@ Added in v1.0.0
 **Signature**
 
 ```ts
-export const tuple = <A, B>(a: A, b: B): [A, B] => ...
+export const tuple = <T extends Array<any>>(...t: T): T => ...
 ```
 
 Added in v1.0.0
diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md
index 66c4d973..6929e82a 100644
--- a/docs/modules/index.ts.md
+++ b/docs/modules/index.ts.md
@@ -66,6 +66,7 @@ parent: Modules
 - [monoid (export)](#monoid-export)
 - [monoidal (export)](#monoidal-export)
 - [nonEmptyArray (export)](#nonemptyarray-export)
+- [nonEmptyArray2v (export)](#nonemptyarray2v-export)
 - [option (export)](#option-export)
 - [optionT (export)](#optiont-export)
 - [ord (export)](#ord-export)
@@ -570,6 +571,14 @@ export { monoidal }
 export { nonEmptyArray }
 ```
 
+# nonEmptyArray2v (export)
+
+**Signature**
+
+```ts
+export { nonEmptyArray2v }
+```
+
 # option (export)
 
 **Signature**
diff --git a/dtslint/ts3.1/index.ts b/dtslint/ts3.1/index.ts
index d9d825ee..4e309676 100644
--- a/dtslint/ts3.1/index.ts
+++ b/dtslint/ts3.1/index.ts
@@ -24,6 +24,8 @@ import * as SM from '../../src/StrMap'
 import * as Fo from '../../src/Foldable'
 import * as Or from '../../src/Ord'
 import * as Fu from '../../src/function'
+import * as Ring from '../../src/Ring'
+import * as Field from '../../src/Field'
 
 const double = (n: number): number => n * 2
 const len = (s: string): number => s.length
@@ -92,6 +94,26 @@ sequenceSf2({ sequenceS5, sequenceS9 })
 
 sequenceSf2({ sequenceS5, sequenceS6, sequenceS7 }) // $ExpectType ReaderTaskEither<{ a: number; }, string, { sequenceS5: number; sequenceS6: string; sequenceS7: boolean; }>
 
+// sequenceT
+
+const sequenceTf1 = Apy.sequenceT(E.either)
+
+// $ExpectError
+sequenceTf1([])
+// $ExpectError
+sequenceTf1(sequenceS1, sequenceS4)
+
+sequenceTf1(sequenceS1, sequenceS2, sequenceS3) // $ExpectType Either<string, [number, string, boolean]>
+
+const sequenceTf2 = Apy.sequenceT(RTE.readerTaskEither)
+
+// $ExpectError
+sequenceTf2(sequenceS5, sequenceS8)
+// $ExpectError
+sequenceTf2(sequenceS5, sequenceS9)
+
+sequenceTf2(sequenceS5, sequenceS6, sequenceS7) // $ExpectType ReaderTaskEither<{ a: number; }, string, [number, string, boolean]>
+
 //
 // Unfoldable
 //
@@ -267,6 +289,18 @@ declare const fromFoldableF1: Fo.Foldable<'Test'>
 declare const fromFoldableInput1: H.HKT<'Test', ['a' | 'b', number]>
 const fromFoldable1 = R.fromFoldable(fromFoldableF1)(fromFoldableInput1, a => a) // $ExpectType Record<"a" | "b", number>
 
+//
+// Setoid
+//
+
+const Setoid1 = Se.getTupleSetoid(Se.setoidString, Se.setoidNumber, Se.setoidBoolean) // $ExpectType Setoid<[string, number, boolean]>
+
+//
+// Ord
+//
+
+const Ord1 = Or.getTupleOrd(Or.ordString, Or.ordNumber, Or.ordBoolean) // $ExpectType Ord<[string, number, boolean]>
+
 //
 // Semigroup
 //
@@ -274,6 +308,8 @@ const fromFoldable1 = R.fromFoldable(fromFoldableF1)(fromFoldableInput1, a => a)
 const Sem1 = S.getDictionarySemigroup(S.semigroupSum) // $ExpectType Semigroup<Record<string, number>>
 const Sem2 = S.getDictionarySemigroup<Keys, number>(S.semigroupSum) // $ExpectType Semigroup<Record<Keys, number>>
 
+const Sem3 = S.getTupleSemigroup(S.semigroupString, S.semigroupSum, S.semigroupAll) // $ExpectType Semigroup<[string, number, boolean]>
+
 //
 // Monoid
 //
@@ -281,6 +317,14 @@ const Sem2 = S.getDictionarySemigroup<Keys, number>(S.semigroupSum) // $ExpectTy
 const Mon3 = Mon.getDictionaryMonoid(S.semigroupSum) // $ExpectType Monoid<Record<string, number>>
 const Mon4 = Mon.getDictionaryMonoid<Keys, number>(S.semigroupSum) // $ExpectType Monoid<Record<Keys, number>>
 
+const Mon5 = Mon.getTupleMonoid(Mon.monoidString, Mon.monoidSum, Mon.monoidAll) // $ExpectType Monoid<[string, number, boolean]>
+
+//
+// Ring
+//
+
+const Ring1 = Ring.getTupleRing(Field.fieldNumber, Field.fieldNumber, Field.fieldNumber) // $ExpectType Ring<[number, number, number]>
+
 //
 // StrMap
 //
diff --git a/jest.config.js b/jest.config.js
index 0c89b7e1..9b868ff7 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -15,5 +15,6 @@ module.exports = {
       lines: 100,
       statements: 100
     }
-  }
+  },
+  modulePathIgnorePatterns: ['property-test']
 }
diff --git a/package-lock.json b/package-lock.json
index b3043d90..591ed373 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "1.14.3",
+  "version": "1.14.4",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -2045,6 +2045,16 @@
       "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
       "dev": true
     },
+    "fast-check": {
+      "version": "1.12.1",
+      "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-1.12.1.tgz",
+      "integrity": "sha512-JRoqLwalxb46RX/iVJyvErHXqojVggXqg+jRAWU2BfuLtxZYq5uetibLLousdUKcX+u8jFXyIn7ezSG1Rab/lQ==",
+      "dev": true,
+      "requires": {
+        "lorem-ipsum": "~1.0.6",
+        "pure-rand": "^1.6.2"
+      }
+    },
     "fast-deep-equal": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
@@ -4610,6 +4620,23 @@
         "js-tokens": "^3.0.0 || ^4.0.0"
       }
     },
+    "lorem-ipsum": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/lorem-ipsum/-/lorem-ipsum-1.0.6.tgz",
+      "integrity": "sha512-Rx4XH8X4KSDCKAVvWGYlhAfNqdUP5ZdT4rRyf0jjrvWgtViZimDIlopWNfn/y3lGM5K4uuiAoY28TaD+7YKFrQ==",
+      "dev": true,
+      "requires": {
+        "minimist": "~1.2.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+          "dev": true
+        }
+      }
+    },
     "lru-cache": {
       "version": "4.1.5",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
@@ -5447,6 +5474,12 @@
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
+    "pure-rand": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-1.6.2.tgz",
+      "integrity": "sha512-HNwHOH63m7kCxe0kWEe5jSLwJiL2N83RUUN8POniFuZS+OsbFcMWlvXgxIU2nwKy2zYG2bQan40WBNK4biYPRg==",
+      "dev": true
+    },
     "qs": {
       "version": "6.5.2",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
diff --git a/package.json b/package.json
index 6912d18c..29291079 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
     "doctoc": "^1.4.0",
     "doctrine": "2.0.0",
     "dtslint": "github:gcanti/dtslint",
+    "fast-check": "^1.12.1",
     "glob": "^7.1.3",
     "jest": "^23.6.0",
     "mocha": "^5.2.0",
diff --git a/src/Apply.ts b/src/Apply.ts
index 3895901b..7a15c006 100644
--- a/src/Apply.ts
+++ b/src/Apply.ts
@@ -231,235 +231,6 @@ export function getSemigroup<F, A>(F: Apply<F>, S: Semigroup<A>): () => Semigrou
   })
 }
 
-export interface SequenceT3<F extends URIS3> {
-  <U, L, A>(a: Type3<F, U, L, A>): Type3<F, U, L, [A]>
-  <U, L, A, B>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>): Type3<F, U, L, [A, B]>
-  <U, L, A, B, C>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>, c: Type3<F, U, L, C>): Type3<F, U, L, [A, B, C]>
-  <U, L, A, B, C, D>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>, c: Type3<F, U, L, C>, d: Type3<F, U, L, D>): Type3<
-    F,
-    U,
-    L,
-    [A, B, C, D]
-  >
-  <U, L, A, B, C, D, E>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>
-  ): Type3<F, U, L, [A, B, C, D, E]>
-  <U, L, A, B, C, D, E, G>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>
-  ): Type3<F, U, L, [A, B, C, D, E, G]>
-  <U, L, A, B, C, D, E, G, H>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>,
-    h: Type3<F, U, L, H>
-  ): Type3<F, U, L, [A, B, C, D, E, G, H]>
-  <U, L, A, B, C, D, E, G, H, I>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>,
-    h: Type3<F, U, L, H>,
-    i: Type3<F, U, L, I>
-  ): Type3<F, U, L, [A, B, C, D, E, G, H, I]>
-}
-export interface SequenceT3C<F extends URIS3, U, L> {
-  <A>(a: Type3<F, U, L, A>): Type3<F, U, L, [A]>
-  <A, B>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>): Type3<F, U, L, [A, B]>
-  <A, B, C>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>, c: Type3<F, U, L, C>): Type3<F, U, L, [A, B, C]>
-  <A, B, C, D>(a: Type3<F, U, L, A>, b: Type3<F, U, L, B>, c: Type3<F, U, L, C>, d: Type3<F, U, L, D>): Type3<
-    F,
-    U,
-    L,
-    [A, B, C, D]
-  >
-  <A, B, C, D, E>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>
-  ): Type3<F, U, L, [A, B, C, D, E]>
-  <A, B, C, D, E, G>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>
-  ): Type3<F, U, L, [A, B, C, D, E, G]>
-  <A, B, C, D, E, G, H>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>,
-    h: Type3<F, U, L, H>
-  ): Type3<F, U, L, [A, B, C, D, E, G, H]>
-  <A, B, C, D, E, G, H, I>(
-    a: Type3<F, U, L, A>,
-    b: Type3<F, U, L, B>,
-    c: Type3<F, U, L, C>,
-    d: Type3<F, U, L, D>,
-    e: Type3<F, U, L, E>,
-    g: Type3<F, U, L, G>,
-    h: Type3<F, U, L, H>,
-    i: Type3<F, U, L, I>
-  ): Type3<F, U, L, [A, B, C, D, E, G, H, I]>
-}
-export interface SequenceT2<F extends URIS2> {
-  <L, A>(a: Type2<F, L, A>): Type2<F, L, [A]>
-  <L, A, B>(a: Type2<F, L, A>, b: Type2<F, L, B>): Type2<F, L, [A, B]>
-  <L, A, B, C>(a: Type2<F, L, A>, b: Type2<F, L, B>, c: Type2<F, L, C>): Type2<F, L, [A, B, C]>
-  <L, A, B, C, D>(a: Type2<F, L, A>, b: Type2<F, L, B>, c: Type2<F, L, C>, d: Type2<F, L, D>): Type2<F, L, [A, B, C, D]>
-  <L, A, B, C, D, E>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>
-  ): Type2<F, L, [A, B, C, D, E]>
-  <L, A, B, C, D, E, G>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>
-  ): Type2<F, L, [A, B, C, D, E, G]>
-  <L, A, B, C, D, E, G, H>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>,
-    h: Type2<F, L, H>
-  ): Type2<F, L, [A, B, C, D, E, G, H]>
-  <L, A, B, C, D, E, G, H, I>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>,
-    h: Type2<F, L, H>,
-    i: Type2<F, L, I>
-  ): Type2<F, L, [A, B, C, D, E, G, H, I]>
-}
-export interface SequenceT2C<F extends URIS2, L> {
-  <A>(a: Type2<F, L, A>): Type2<F, L, [A]>
-  <A, B>(a: Type2<F, L, A>, b: Type2<F, L, B>): Type2<F, L, [A, B]>
-  <A, B, C>(a: Type2<F, L, A>, b: Type2<F, L, B>, c: Type2<F, L, C>): Type2<F, L, [A, B, C]>
-  <A, B, C, D>(a: Type2<F, L, A>, b: Type2<F, L, B>, c: Type2<F, L, C>, d: Type2<F, L, D>): Type2<F, L, [A, B, C, D]>
-  <A, B, C, D, E>(a: Type2<F, L, A>, b: Type2<F, L, B>, c: Type2<F, L, C>, d: Type2<F, L, D>, e: Type2<F, L, E>): Type2<
-    F,
-    L,
-    [A, B, C, D, E]
-  >
-  <A, B, C, D, E, G>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>
-  ): Type2<F, L, [A, B, C, D, E, G]>
-  <A, B, C, D, E, G, H>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>,
-    h: Type2<F, L, H>
-  ): Type2<F, L, [A, B, C, D, E, G, H]>
-  <A, B, C, D, E, G, H, I>(
-    a: Type2<F, L, A>,
-    b: Type2<F, L, B>,
-    c: Type2<F, L, C>,
-    d: Type2<F, L, D>,
-    e: Type2<F, L, E>,
-    g: Type2<F, L, G>,
-    h: Type2<F, L, H>,
-    i: Type2<F, L, I>
-  ): Type2<F, L, [A, B, C, D, E, G, H, I]>
-}
-export interface SequenceT1<F extends URIS> {
-  <A>(a: Type<F, A>): Type<F, [A]>
-  <A, B>(a: Type<F, A>, b: Type<F, B>): Type<F, [A, B]>
-  <A, B, C>(a: Type<F, A>, b: Type<F, B>, c: Type<F, C>): Type<F, [A, B, C]>
-  <A, B, C, D>(a: Type<F, A>, b: Type<F, B>, c: Type<F, C>, d: Type<F, D>): Type<F, [A, B, C, D]>
-  <A, B, C, D, E>(a: Type<F, A>, b: Type<F, B>, c: Type<F, C>, d: Type<F, D>, e: Type<F, E>): Type<F, [A, B, C, D, E]>
-  <A, B, C, D, E, G>(a: Type<F, A>, b: Type<F, B>, c: Type<F, C>, d: Type<F, D>, e: Type<F, E>, g: Type<F, G>): Type<
-    F,
-    [A, B, C, D, E, G]
-  >
-  <A, B, C, D, E, G, H>(
-    a: Type<F, A>,
-    b: Type<F, B>,
-    c: Type<F, C>,
-    d: Type<F, D>,
-    e: Type<F, E>,
-    g: Type<F, G>,
-    h: Type<F, H>
-  ): Type<F, [A, B, C, D, E, G, H]>
-  <A, B, C, D, E, G, H, I>(
-    a: Type<F, A>,
-    b: Type<F, B>,
-    c: Type<F, C>,
-    d: Type<F, D>,
-    e: Type<F, E>,
-    g: Type<F, G>,
-    h: Type<F, H>,
-    i: Type<F, I>
-  ): Type<F, [A, B, C, D, E, G, H, I]>
-}
-export interface SequenceT<F> {
-  <A>(a: HKT<F, A>): HKT<F, [A]>
-  <A, B>(a: HKT<F, A>, b: HKT<F, B>): HKT<F, [A, B]>
-  <A, B, C>(a: HKT<F, A>, b: HKT<F, B>, c: HKT<F, C>): HKT<F, [A, B, C]>
-  <A, B, C, D>(a: HKT<F, A>, b: HKT<F, B>, c: HKT<F, C>, d: HKT<F, D>): HKT<F, [A, B, C, D]>
-  <A, B, C, D, E>(a: HKT<F, A>, b: HKT<F, B>, c: HKT<F, C>, d: HKT<F, D>, e: HKT<F, E>): HKT<F, [A, B, C, D, E]>
-  <A, B, C, D, E, G>(a: HKT<F, A>, b: HKT<F, B>, c: HKT<F, C>, d: HKT<F, D>, e: HKT<F, E>, g: HKT<F, G>): HKT<
-    F,
-    [A, B, C, D, E, G]
-  >
-  <A, B, C, D, E, G, H>(
-    a: HKT<F, A>,
-    b: HKT<F, B>,
-    c: HKT<F, C>,
-    d: HKT<F, D>,
-    e: HKT<F, E>,
-    g: HKT<F, G>,
-    h: HKT<F, H>
-  ): HKT<F, [A, B, C, D, E, G, H]>
-  <A, B, C, D, E, G, H, I>(
-    a: HKT<F, A>,
-    b: HKT<F, B>,
-    c: HKT<F, C>,
-    d: HKT<F, D>,
-    e: HKT<F, E>,
-    g: HKT<F, G>,
-    h: HKT<F, H>,
-    i: HKT<F, I>
-  ): HKT<F, [A, B, C, D, E, G, H, I]>
-}
-
 const tupleConstructors: { [key: string]: Function1<any, any> } = {}
 
 /**
@@ -476,13 +247,37 @@ const tupleConstructors: { [key: string]: Function1<any, any> } = {}
  *
  * @since 1.5.0
  */
-export function sequenceT<F extends URIS3, U, L>(F: Apply3<F>): SequenceT3<F>
-export function sequenceT<F extends URIS3, U, L>(F: Apply3C<F, U, L>): SequenceT3C<F, U, L>
-export function sequenceT<F extends URIS2>(F: Apply2<F>): SequenceT2<F>
-export function sequenceT<F extends URIS2, L>(F: Apply2C<F, L>): SequenceT2C<F, L>
-export function sequenceT<F extends URIS>(F: Apply1<F>): SequenceT1<F>
-export function sequenceT<F>(F: Apply<F>): SequenceT<F>
-export function sequenceT<F>(F: Apply<F>): SequenceT<F> {
+export function sequenceT<F extends URIS3>(
+  F: Apply3<F>
+): <U, L, T extends Array<Type3<F, U, L, any>>>(
+  ...t: T & { 0: Type3<F, U, L, any> }
+) => Type3<F, U, L, { [K in keyof T]: T[K] extends Type3<F, U, L, infer A> ? A : never }>
+export function sequenceT<F extends URIS3, U, L>(
+  F: Apply3C<F, U, L>
+): <T extends Array<Type3<F, U, L, any>>>(
+  ...t: T & { 0: Type3<F, U, L, any> }
+) => Type3<F, U, L, { [K in keyof T]: T[K] extends Type3<F, U, L, infer A> ? A : never }>
+export function sequenceT<F extends URIS2>(
+  F: Apply2<F>
+): <L, T extends Array<Type2<F, L, any>>>(
+  ...t: T & { 0: Type2<F, L, any> }
+) => Type2<F, L, { [K in keyof T]: T[K] extends Type2<F, L, infer A> ? A : never }>
+export function sequenceT<F extends URIS2, L>(
+  F: Apply2C<F, L>
+): <T extends Array<Type2<F, L, any>>>(
+  ...t: T & { 0: Type2<F, L, any> }
+) => Type2<F, L, { [K in keyof T]: T[K] extends Type2<F, L, infer A> ? A : never }>
+export function sequenceT<F extends URIS>(
+  F: Apply1<F>
+): <T extends Array<Type<F, any>>>(
+  ...t: T & { 0: Type<F, any> }
+) => Type<F, { [K in keyof T]: T[K] extends Type<F, infer A> ? A : never }>
+export function sequenceT<F>(
+  F: Apply<F>
+): <T extends Array<HKT<F, any>>>(
+  ...t: T & { 0: HKT<F, any> }
+) => HKT<F, { [K in keyof T]: T[K] extends HKT<F, infer A> ? A : never }>
+export function sequenceT<F>(F: Apply<F>): (...args: Array<any>) => HKT<F, any> {
   return (...args: Array<any>) => {
     const len = args.length
     let f = tupleConstructors[len]
diff --git a/src/Monoid.ts b/src/Monoid.ts
index 6f7b9e9e..1054b70c 100644
--- a/src/Monoid.ts
+++ b/src/Monoid.ts
@@ -33,13 +33,26 @@ export const fold = <A>(M: Monoid<A>): ((as: Array<A>) => A) => {
 }
 
 /**
+ * Given a tuple of monoids returns a monoid for the tuple
+ *
+ * @example
+ * import { getTupleMonoid, monoidString, monoidSum, monoidAll } from 'fp-ts/lib/Monoid'
+ *
+ * const M1 = getTupleMonoid(monoidString, monoidSum)
+ * assert.deepStrictEqual(M1.concat(['a', 1], ['b', 2]), ['ab', 3])
+ *
+ * const M2 = getTupleMonoid(monoidString, monoidSum, monoidAll)
+ * assert.deepStrictEqual(M2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
+ *
  * @since 1.0.0
  */
-export const getTupleMonoid = <A, B>(MA: Monoid<A>, MB: Monoid<B>): Monoid<[A, B]> => {
+export const getTupleMonoid = <T extends Array<Monoid<any>>>(
+  ...monoids: T
+): Monoid<{ [K in keyof T]: T[K] extends Semigroup<infer A> ? A : never }> => {
   return {
-    ...getTupleSemigroup(MA, MB),
-    empty: [MA.empty, MB.empty]
-  }
+    ...getTupleSemigroup(...monoids),
+    empty: monoids.map(m => m.empty)
+  } as any
 }
 
 /**
diff --git a/src/Ord.ts b/src/Ord.ts
index 001ffe6c..336b77da 100644
--- a/src/Ord.ts
+++ b/src/Ord.ts
@@ -156,12 +156,31 @@ export const getSemigroup = <A = never>(): Semigroup<Ord<A>> => {
 }
 
 /**
+ * Given a tuple of `Ord`s returns an `Ord` for the tuple
+ *
+ * @example
+ * import { getTupleOrd, ordString, ordNumber, ordBoolean } from 'fp-ts/lib/Ord'
+ *
+ * const O = getTupleOrd(ordString, ordNumber, ordBoolean)
+ * assert.strictEqual(O.compare(['a', 1, true], ['b', 2, true]), -1)
+ * assert.strictEqual(O.compare(['a', 1, true], ['a', 2, true]), -1)
+ * assert.strictEqual(O.compare(['a', 1, true], ['a', 1, false]), 1)
+ *
  * @since 1.14.3
  */
-export const getTupleOrd = <A, B>(OA: Ord<A>, OB: Ord<B>): Ord<[A, B]> => {
-  return fromCompare(([xa, xb], [ya, yb]) => {
-    const r = OA.compare(xa, ya)
-    return r === 0 ? OB.compare(xb, yb) : r
+export const getTupleOrd = <T extends Array<Ord<any>>>(
+  ...ords: T
+): Ord<{ [K in keyof T]: T[K] extends Ord<infer A> ? A : never }> => {
+  const len = ords.length
+  return fromCompare((x, y) => {
+    let i = 0
+    for (; i < len - 1; i++) {
+      const r = ords[i].compare(x[i], y[i])
+      if (r !== 0) {
+        return r
+      }
+    }
+    return ords[i].compare(x[i], y[i])
   })
 }
 
diff --git a/src/Ring.ts b/src/Ring.ts
index cbcabf01..3ce0db77 100644
--- a/src/Ring.ts
+++ b/src/Ring.ts
@@ -36,16 +36,31 @@ export const negate = <A>(ring: Ring<A>) => (a: A): A => {
 }
 
 /**
+ * Given a tuple of `Ring`s returns a `Ring` for the tuple
+ *
+ * @example
+ * import { getTupleRing } from 'fp-ts/lib/Ring'
+ * import { fieldNumber } from 'fp-ts/lib/Field'
+ *
+ * const R = getTupleRing(fieldNumber, fieldNumber, fieldNumber)
+ * assert.deepStrictEqual(R.add([1, 2, 3], [4, 5, 6]), [5, 7, 9])
+ * assert.deepStrictEqual(R.mul([1, 2, 3], [4, 5, 6]), [4, 10, 18])
+ * assert.deepStrictEqual(R.one, [1, 1, 1])
+ * assert.deepStrictEqual(R.sub([1, 2, 3], [4, 5, 6]), [-3, -3, -3])
+ * assert.deepStrictEqual(R.zero, [0, 0, 0])
+ *
  * @since 1.14.3
  */
-export const getTupleRing = <A, B>(RA: Ring<A>, RB: Ring<B>): Ring<[A, B]> => {
+export const getTupleRing = <T extends Array<Ring<any>>>(
+  ...rings: T
+): Ring<{ [K in keyof T]: T[K] extends Ring<infer A> ? A : never }> => {
   return {
-    add: ([a1, b1], [a2, b2]) => [RA.add(a1, a2), RB.add(b1, b2)],
-    zero: [RA.zero, RB.zero],
-    mul: ([a1, b1], [a2, b2]) => [RA.mul(a1, a2), RB.mul(b1, b2)],
-    one: [RA.one, RB.one],
-    sub: ([a1, b1], [a2, b2]) => [RA.sub(a1, a2), RB.sub(b1, b2)]
-  }
+    add: (x: any, y: any) => rings.map((R, i) => R.add(x[i], y[i])),
+    zero: rings.map(R => R.zero),
+    mul: (x: any, y: any) => rings.map((R, i) => R.mul(x[i], y[i])),
+    one: rings.map(R => R.one),
+    sub: (x: any, y: any) => rings.map((R, i) => R.sub(x[i], y[i]))
+  } as any
 }
 
 /**
diff --git a/src/Semigroup.ts b/src/Semigroup.ts
index e398c59c..096c7542 100644
--- a/src/Semigroup.ts
+++ b/src/Semigroup.ts
@@ -33,11 +33,24 @@ export const getLastSemigroup = <A = never>(): Semigroup<A> => {
 }
 
 /**
+ * Given a tuple of semigroups returns a semigroup for the tuple
+ *
+ * @example
+ * import { getTupleSemigroup, semigroupString, semigroupSum, semigroupAll } from 'fp-ts/lib/Semigroup'
+ *
+ * const S1 = getTupleSemigroup(semigroupString, semigroupSum)
+ * assert.deepStrictEqual(S1.concat(['a', 1], ['b', 2]), ['ab', 3])
+ *
+ * const S2 = getTupleSemigroup(semigroupString, semigroupSum, semigroupAll)
+ * assert.deepStrictEqual(S2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
+ *
  * @since 1.14.0
  */
-export const getTupleSemigroup = <A, B>(SA: Semigroup<A>, SB: Semigroup<B>): Semigroup<[A, B]> => {
+export const getTupleSemigroup = <T extends Array<Semigroup<any>>>(
+  ...semigroups: T
+): Semigroup<{ [K in keyof T]: T[K] extends Semigroup<infer A> ? A : never }> => {
   return {
-    concat: ([xa, xb], [ya, yb]) => [SA.concat(xa, ya), SB.concat(xb, yb)]
+    concat: (x, y) => semigroups.map((s, i) => s.concat(x[i], y[i])) as any
   }
 }
 
diff --git a/src/Setoid.ts b/src/Setoid.ts
index 25a689b4..2b0dadb7 100644
--- a/src/Setoid.ts
+++ b/src/Setoid.ts
@@ -85,10 +85,23 @@ export const getRecordSetoid = <O extends { [key: string]: any }>(
 }
 
 /**
+ * Given a tuple of `Setoid`s returns a `Setoid` for the tuple
+ *
+ * @example
+ * import { getTupleSetoid, setoidString, setoidNumber, setoidBoolean } from 'fp-ts/lib/Setoid'
+ *
+ * const S = getTupleSetoid(setoidString, setoidNumber, setoidBoolean)
+ * assert.strictEqual(S.equals(['a', 1, true], ['a', 1, true]), true)
+ * assert.strictEqual(S.equals(['a', 1, true], ['b', 1, true]), false)
+ * assert.strictEqual(S.equals(['a', 1, true], ['a', 2, true]), false)
+ * assert.strictEqual(S.equals(['a', 1, true], ['a', 1, false]), false)
+ *
  * @since 1.14.2
  */
-export const getTupleSetoid = <A, B>(SA: Setoid<A>, SB: Setoid<B>): Setoid<[A, B]> => {
-  return fromEquals((a, b) => SA.equals(a[0], b[0]) && SB.equals(a[1], b[1]))
+export const getTupleSetoid = <T extends Array<Setoid<any>>>(
+  ...setoids: T
+): Setoid<{ [K in keyof T]: T[K] extends Setoid<infer A> ? A : never }> => {
+  return fromEquals((x, y) => setoids.every((S, i) => S.equals(x[i], y[i])))
 }
 
 /**


Test patch:
diff --git a/test/Apply.ts b/test/Apply.ts
index d029eb0b..9e773508 100644
--- a/test/Apply.ts
+++ b/test/Apply.ts
@@ -1,7 +1,12 @@
 import * as assert from 'assert'
 import { applyFirst, applySecond, liftA2, liftA3, liftA4, sequenceT, sequenceS } from '../src/Apply'
 import { either, left, right } from '../src/Either'
-import { none, option, some } from '../src/Option'
+import { none, option, some, isSome, isNone } from '../src/Option'
+import * as fc from 'fast-check'
+import { getSome } from './property-test/Option'
+import { nonEmptyArray } from './property-test/NonEmptyArray2v'
+import { catOptions, getSetoid } from '../src/Array'
+import { fromEquals } from '../src/Setoid'
 
 describe('Apply', () => {
   const r1 = right<string, number>(1)
@@ -64,13 +69,24 @@ describe('Apply', () => {
 
   it('sequenceT', () => {
     const sequenceTOption = sequenceT(option)
-    const sequenceTEither = sequenceT(either)
     assert.deepStrictEqual(sequenceTOption(some(1)), some([1]))
     assert.deepStrictEqual(sequenceTOption(some(1), some('2')), some([1, '2']))
     assert.deepStrictEqual(sequenceTOption(some(1), some('2'), none), none)
-    assert.deepStrictEqual(sequenceTEither(right(1)), right([1]))
-    assert.deepStrictEqual(sequenceTEither(right(1), right('2')), right([1, '2']))
-    assert.deepStrictEqual(sequenceTEither(right(1), right('2'), left('foo')), left('foo'))
+
+    const S = getSetoid(fromEquals((x, y) => x === y))
+    const somes = getSome(fc.oneof<string | number>(fc.string(), fc.integer()))
+    const allSomesInput = nonEmptyArray(somes)
+    const maybeNoneInput = nonEmptyArray(fc.oneof(fc.constant(none), somes))
+    const input = fc.oneof(allSomesInput, maybeNoneInput)
+    fc.assert(
+      fc.property(input, options => {
+        const x = sequenceTOption(...(options as any))
+        return (
+          (options.every(isSome) && x.isSome() && S.equals(x.value as any, catOptions(options))) ||
+          (options.some(isNone) && x.isNone())
+        )
+      })
+    )
   })
 
   it('sequenceS', () => {
diff --git a/test/Monoid.ts b/test/Monoid.ts
index 58135ee5..c1e09cc9 100644
--- a/test/Monoid.ts
+++ b/test/Monoid.ts
@@ -13,12 +13,20 @@ import {
   monoidSum,
   getProductMonoid,
   getMeetMonoid,
-  getJoinMonoid
+  getJoinMonoid,
+  getTupleMonoid
 } from '../src/Monoid'
 import { semigroupSum } from '../src/Semigroup'
 import { boundedNumber } from '../src/Bounded'
 
 describe('Monoid', () => {
+  it('getTupleMonoid', () => {
+    const M1 = getTupleMonoid(monoidString, monoidSum)
+    assert.deepStrictEqual(M1.concat(['a', 1], ['b', 2]), ['ab', 3])
+    const M2 = getTupleMonoid(monoidString, monoidSum, monoidAll)
+    assert.deepStrictEqual(M2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
+  })
+
   it('fold', () => {
     assert.strictEqual(fold(monoidSum)([1, 2, 3]), 6)
   })
diff --git a/test/Ord.ts b/test/Ord.ts
index f52fc154..de1bbb86 100644
--- a/test/Ord.ts
+++ b/test/Ord.ts
@@ -12,10 +12,19 @@ import {
   ordString,
   lessThanOrEq,
   greaterThanOrEq,
-  fromCompare
+  fromCompare,
+  getTupleOrd,
+  ordBoolean
 } from '../src/Ord'
 
 describe('Ord', () => {
+  it('getTupleOrd', () => {
+    const O = getTupleOrd(ordString, ordNumber, ordBoolean)
+    assert.strictEqual(O.compare(['a', 1, true], ['b', 2, true]), -1)
+    assert.strictEqual(O.compare(['a', 1, true], ['a', 2, true]), -1)
+    assert.strictEqual(O.compare(['a', 1, true], ['a', 1, false]), 1)
+  })
+
   it('getSemigroup', () => {
     type T = [number, string]
     const tuples: Array<T> = [[2, 'c'], [1, 'b'], [2, 'a'], [1, 'c']]
diff --git a/test/Ring.ts b/test/Ring.ts
index ee759cd3..599bc83c 100644
--- a/test/Ring.ts
+++ b/test/Ring.ts
@@ -1,8 +1,17 @@
 import * as assert from 'assert'
 import { fieldNumber } from '../src/Field'
-import { getProductRing, negate, getFunctionRing } from '../src/Ring'
+import { getProductRing, negate, getFunctionRing, getTupleRing } from '../src/Ring'
 
 describe('Ring', () => {
+  it('getTupleRing', () => {
+    const R = getTupleRing(fieldNumber, fieldNumber, fieldNumber)
+    assert.deepStrictEqual(R.add([1, 2, 3], [4, 5, 6]), [5, 7, 9])
+    assert.deepStrictEqual(R.mul([1, 2, 3], [4, 5, 6]), [4, 10, 18])
+    assert.deepStrictEqual(R.one, [1, 1, 1])
+    assert.deepStrictEqual(R.sub([1, 2, 3], [4, 5, 6]), [-3, -3, -3])
+    assert.deepStrictEqual(R.zero, [0, 0, 0])
+  })
+
   it('getProductRing', () => {
     // tslint:disable-next-line: deprecation
     const R = getProductRing(fieldNumber, fieldNumber)
diff --git a/test/Semigroup.ts b/test/Semigroup.ts
index 57d2ca3f..8a195905 100644
--- a/test/Semigroup.ts
+++ b/test/Semigroup.ts
@@ -13,10 +13,20 @@ import {
   getRecordSemigroup,
   semigroupProduct,
   semigroupSum,
-  semigroupVoid
+  semigroupVoid,
+  getTupleSemigroup,
+  semigroupString,
+  semigroupAll
 } from '../src/Semigroup'
 
 describe('Semigroup', () => {
+  it('getTupleSemigroup', () => {
+    const S1 = getTupleSemigroup(semigroupString, semigroupSum)
+    assert.deepStrictEqual(S1.concat(['a', 1], ['b', 2]), ['ab', 3])
+    const S2 = getTupleSemigroup(semigroupString, semigroupSum, semigroupAll)
+    assert.deepStrictEqual(S2.concat(['a', 1, true], ['b', 2, false]), ['ab', 3, false])
+  })
+
   it('fold', () => {
     assert.strictEqual(fold(monoidString)('')(['a', 'b', 'c']), 'abc')
   })
diff --git a/test/Setoid.ts b/test/Setoid.ts
index 80b51246..3134bd8a 100644
--- a/test/Setoid.ts
+++ b/test/Setoid.ts
@@ -6,10 +6,20 @@ import {
   setoidDate,
   setoidNumber,
   setoidString,
-  fromEquals
+  fromEquals,
+  getTupleSetoid,
+  setoidBoolean
 } from '../src/Setoid'
 
 describe('Setoid', () => {
+  it('getTupleSetoid', () => {
+    const S = getTupleSetoid(setoidString, setoidNumber, setoidBoolean)
+    assert.strictEqual(S.equals(['a', 1, true], ['a', 1, true]), true)
+    assert.strictEqual(S.equals(['a', 1, true], ['b', 1, true]), false)
+    assert.strictEqual(S.equals(['a', 1, true], ['a', 2, true]), false)
+    assert.strictEqual(S.equals(['a', 1, true], ['a', 1, false]), false)
+  })
+
   interface Person {
     name: string
     age: number
diff --git a/test/property-test/NonEmptyArray2v.ts b/test/property-test/NonEmptyArray2v.ts
new file mode 100644
index 00000000..80aec0ca
--- /dev/null
+++ b/test/property-test/NonEmptyArray2v.ts
@@ -0,0 +1,9 @@
+import * as fc from 'fast-check'
+import { NonEmptyArray } from '../../src/NonEmptyArray2v'
+
+/**
+ * Returns an `Arbitrary` that yelds a non empty array
+ */
+export function nonEmptyArray<A>(arb: fc.Arbitrary<A>): fc.Arbitrary<NonEmptyArray<A>> {
+  return fc.array(arb, 1, 100) as any
+}
diff --git a/test/property-test/Option.ts b/test/property-test/Option.ts
new file mode 100644
index 00000000..cfe1d751
--- /dev/null
+++ b/test/property-test/Option.ts
@@ -0,0 +1,26 @@
+import * as fc from 'fast-check'
+import { Option, some, none } from '../../src/Option'
+
+/**
+ * Returns an `Arbitrary` that yelds only `some`s
+ * @since 0.0.2
+ */
+export function getSome<A>(arb: fc.Arbitrary<A>): fc.Arbitrary<Option<A>> {
+  return arb.map(some)
+}
+
+/**
+ * Returns an `Arbitrary` that yelds only `none`s
+ * @since 0.0.2
+ */
+export function getNone<A>(): fc.Arbitrary<Option<A>> {
+  return fc.constant(none)
+}
+
+/**
+ * Returns an `Arbitrary` that yelds both `some`s and `none`s
+ * @since 0.0.2
+ */
+export function getOption<A>(arb: fc.Arbitrary<A>): fc.Arbitrary<Option<A>> {
+  return fc.oneof(getNone(), getSome(arb))
+}