Repository: gcanti/fp-ts
Pull request #763 (2019-03-10 12:18:00)

Experimental: type level non empty arrays
@yawaramin @sledorze here's a candidate implementation, could you please review?


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f42324cd..e0a83872 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,11 @@
 **Note**: Gaps between patch versions are faulty/broken releases. **Note**: A feature tagged as Experimental is in a
 high state of flux, you're at risk of it changing without notice.
 
+# 1.14.4
+
+- **Polish**
+  - Add overloads to `sequenceT` to allow more arguments (up to 8) (@cdimitroulas)
+
 # 1.14.3
 
 - **Deprecation**
diff --git a/README.md b/README.md
index 71494cb7..6b87fbf1 100644
--- a/README.md
+++ b/README.md
@@ -44,9 +44,9 @@ The idea (faking higher kinded types in TypeScript) is based on [Lightweight hig
 - [Installation and TypeScript compatibility](#installation-and-typescript-compatibility)
 - [Getting started](#getting-started)
 - [Documentation](#documentation)
-  - [Internals](#internals)
   - [Blog posts](#blog-posts)
   - [Tutorials](#tutorials)
+  - [Internals](#internals)
 - [Ecosystem](#ecosystem)
   - [Libraries](#libraries)
   - [Bindings](#bindings)
@@ -78,14 +78,10 @@ If you are coming from JavaScript:
 - read [Mostly adequate guide to FP](https://github.com/MostlyAdequate/mostly-adequate-guide) by [@DrBoolean](https://github.com/DrBoolean)
 - read this [blog series](http://www.tomharding.me/2017/03/03/fantas-eel-and-specification) on functional programming in JavaScript by Tom Harding, and then check out [the code](fantas-eel-and-specification) translated to TypeScript (there's a file for each blog post)
 
-If you are using `ramda`
+If you are using `ramda`:
 
 - [Comparison with ramda](https://github.com/gcanti/fp-ts/blob/master/ramda.md)
 
-If you are coming from TypeScript:
-
-- [How to write type class instances for your data structures](https://github.com/gcanti/fp-ts/blob/master/HKT.md)
-
 If you are coming from Haskell or Purescript:
 
 - [Comparison with PureScript](https://github.com/gcanti/fp-ts/blob/master/fp-ts-for-purescripters.md)
@@ -93,17 +89,20 @@ If you are coming from Haskell or Purescript:
 # Documentation
 
 - [API Reference](https://gcanti.github.io/fp-ts)
-
-## Internals
-
-- [Code conventions](https://github.com/gcanti/fp-ts/blob/master/code-conventions.md)
+- [How to write type class instances for your data structures](https://github.com/gcanti/fp-ts/blob/master/HKT.md)
 
 ## Blog posts
 
 - [Interoperability with non functional code using fp-ts](https://dev.to/gcanti/interoperability-with-non-functional-code-using-fp-ts-432e)
-- [Functional design: combinators](https://dev.to/gcanti/functional-design-combinators-14pn)
-- [Functional design: how to make the `time` combinator more general](https://dev.to/gcanti/functional-design-how-to-make-the-time-combinator-more-general-3fge)
-- [Functional design: tagless final](https://dev.to/gcanti/functional-design-tagless-final-332k)
+- "Getting started with fp-ts" series
+  - [Setoid](https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3)
+  - [Ord](https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e)
+  - [Semigroup](https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7)
+- "Functional design" series
+  - [combinators](https://dev.to/gcanti/functional-design-combinators-14pn)
+  - [how to make the `time` combinator more general](https://dev.to/gcanti/functional-design-how-to-make-the-time-combinator-more-general-3fge)
+  - [tagless final](https://dev.to/gcanti/functional-design-tagless-final-332k)
+  - [smart constructors](https://dev.to/gcanti/functional-design-smart-constructors-14nb)
 
 ## Tutorials
 
@@ -113,17 +112,22 @@ If you are coming from Haskell or Purescript:
 
 **Advanced**
 
-- "`fp-ts` to the max" (TypeScript port of John De Goes's "FP to the max" in Scala https://www.youtube.com/watch?v=sxudIMiOo68)
+- "`fp-ts` to the max" (TypeScript port of John De Goes's ["FP to the max"](https://www.youtube.com/watch?v=sxudIMiOo68) in Scala)
   - [Part I](https://github.com/gcanti/fp-ts/blob/master/tutorials/fp-ts-to-the-max-I.ts)
   - [Part II](https://github.com/gcanti/fp-ts/blob/master/tutorials/fp-ts-to-the-max-II.ts)
 - [Free monad and `fp-ts` (code)](https://github.com/gcanti/fp-ts/blob/master/tutorials/Free.ts)
 - [MTL-style in `fp-ts` (code)](https://github.com/gcanti/fp-ts/blob/master/tutorials/mtl.ts)
 - [Type safe finite state machines with `IxIO` (code)](https://github.com/gcanti/fp-ts/blob/master/examples/ixIO.ts)
 
+## Internals
+
+- [Code conventions](https://github.com/gcanti/fp-ts/blob/master/code-conventions.md)
+
 # Ecosystem
 
 ## Libraries
 
+- [fp-ts-contrib](https://github.com/gcanti/fp-ts-contrib) - A community driven utility package for fp-ts
 - [fp-ts-codegen](https://github.com/gcanti/fp-ts-codegen) - TypeScript code generation from a haskell-like syntax for ADT
 - [io-ts](https://github.com/gcanti/io-ts) - TypeScript compatible runtime type system for IO validation
 - [monocle-ts](https://github.com/gcanti/monocle-ts) - Functional optics: a (partial) porting of scala monocle to
diff --git a/docs/index.md b/docs/index.md
index 9492f274..cfa253da 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -21,16 +21,16 @@ A distinctive feature of `fp-ts` with respect to other functional libraries is i
 
 `fp-ts` takes inspiration from [Haskell](https://haskell-lang.org), [PureScript](http://www.purescript.org), and [Scala](https://www.scala-lang.org/), among others.
 
-## Table of Contents
-
 <!-- 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 and TypeScript compatibility](#installation-and-typescript-compatibility)
 - [Getting started](#getting-started)
 - [Documentation](#documentation)
   - [Blog posts](#blog-posts)
   - [Tutorials](#tutorials)
+  - [Internals](#internals)
 - [Ecosystem](#ecosystem)
   - [Libraries](#libraries)
   - [Bindings](#bindings)
@@ -62,28 +62,31 @@ If you are coming from JavaScript:
 - read [Mostly adequate guide to FP](https://github.com/MostlyAdequate/mostly-adequate-guide) by [@DrBoolean](https://github.com/DrBoolean)
 - read this [blog series](http://www.tomharding.me/2017/03/03/fantas-eel-and-specification) on functional programming in JavaScript by Tom Harding, and then check out [the code](fantas-eel-and-specification) translated to TypeScript (there's a file for each blog post)
 
-If you are using `ramda`
+If you are using `ramda`:
 
 - [Comparison with ramda](https://github.com/gcanti/fp-ts/blob/master/ramda.md)
 
-If you are coming from TypeScript:
-
-- [How to write type class instances for your data structures](https://github.com/gcanti/fp-ts/blob/master/HKT.md)
-
 If you are coming from Haskell or Purescript:
 
 - [Comparison with PureScript](https://github.com/gcanti/fp-ts/blob/master/fp-ts-for-purescripters.md)
 
 # Documentation
 
-- [API Reference](https://github.com/gcanti/fp-ts/docs/index.md)
+- [API Reference](https://gcanti.github.io/fp-ts)
+- [How to write type class instances for your data structures](https://github.com/gcanti/fp-ts/blob/master/HKT.md)
 
 ## Blog posts
 
 - [Interoperability with non functional code using fp-ts](https://dev.to/gcanti/interoperability-with-non-functional-code-using-fp-ts-432e)
-- [Functional design: combinators](https://dev.to/gcanti/functional-design-combinators-14pn)
-- [Functional design: how to make the `time` combinator more general](https://dev.to/gcanti/functional-design-how-to-make-the-time-combinator-more-general-3fge)
-- [Functional design: tagless final](https://dev.to/gcanti/functional-design-tagless-final-332k)
+- "Getting started with fp-ts" series
+  - [Setoid](https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3)
+  - [Ord](https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e)
+  - [Semigroup](https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7)
+- "Functional design" series
+  - [combinators](https://dev.to/gcanti/functional-design-combinators-14pn)
+  - [how to make the `time` combinator more general](https://dev.to/gcanti/functional-design-how-to-make-the-time-combinator-more-general-3fge)
+  - [tagless final](https://dev.to/gcanti/functional-design-tagless-final-332k)
+  - [smart constructors](https://dev.to/gcanti/functional-design-smart-constructors-14nb)
 
 ## Tutorials
 
@@ -93,14 +96,22 @@ If you are coming from Haskell or Purescript:
 
 **Advanced**
 
+- "`fp-ts` to the max" (TypeScript port of John De Goes's ["FP to the max"](https://www.youtube.com/watch?v=sxudIMiOo68) in Scala)
+  - [Part I](https://github.com/gcanti/fp-ts/blob/master/tutorials/fp-ts-to-the-max-I.ts)
+  - [Part II](https://github.com/gcanti/fp-ts/blob/master/tutorials/fp-ts-to-the-max-II.ts)
 - [Free monad and `fp-ts` (code)](https://github.com/gcanti/fp-ts/blob/master/tutorials/Free.ts)
-- [MTL-style in `fp-ts` (code)](https://github.com/gcanti/fp-ts/blob/master/examples/mtl.ts)
+- [MTL-style in `fp-ts` (code)](https://github.com/gcanti/fp-ts/blob/master/tutorials/mtl.ts)
 - [Type safe finite state machines with `IxIO` (code)](https://github.com/gcanti/fp-ts/blob/master/examples/ixIO.ts)
 
+## Internals
+
+- [Code conventions](https://github.com/gcanti/fp-ts/blob/master/code-conventions.md)
+
 # Ecosystem
 
 ## Libraries
 
+- [fp-ts-contrib](https://github.com/gcanti/fp-ts-contrib) - A community driven utility package for fp-ts
 - [fp-ts-codegen](https://github.com/gcanti/fp-ts-codegen) - TypeScript code generation from a haskell-like syntax for ADT
 - [io-ts](https://github.com/gcanti/io-ts) - TypeScript compatible runtime type system for IO validation
 - [monocle-ts](https://github.com/gcanti/monocle-ts) - Functional optics: a (partial) porting of scala monocle to
@@ -113,6 +124,7 @@ If you are coming from Haskell or Purescript:
 - [retry-ts](https://github.com/gcanti/retry-ts) - Retry combinators for monadic actions that may fail
 - [fp-ts-local-storage](https://github.com/gcanti/fp-ts-local-storage) - fp-ts bindings for LocalStorage
 - [circuit-breaker-monad](https://github.com/YBogomolov/circuit-breaker-monad) - Circuit Breaker pattern as a monad
+- [waveguide](https://github.com/rzeigler/waveguide) - Bifunctor effect type and concurrent data structures.
 
 ## Bindings
 
@@ -120,6 +132,3 @@ If you are coming from Haskell or Purescript:
 - [fp-ts-fluture](https://github.com/gcanti/fp-ts-fluture) - fp-ts bindings for Fluture
 - [fp-ts-most](https://github.com/joshburgess/fp-ts-most) - fp-ts bindings for @most/core
 
-# License
-
-The MIT License (MIT)
diff --git a/docs/modules/Apply.ts.md b/docs/modules/Apply.ts.md
index 4a0b413e..35b294ab 100644
--- a/docs/modules/Apply.ts.md
+++ b/docs/modules/Apply.ts.md
@@ -116,6 +116,29 @@ export interface SequenceT<F> {
   <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]>
 }
 ```
 
@@ -130,6 +153,29 @@ export interface SequenceT1<F extends URIS> {
   <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]>
 }
 ```
 
@@ -150,6 +196,33 @@ export interface SequenceT2<F extends URIS2> {
     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]>
 }
 ```
 
@@ -168,6 +241,33 @@ export interface SequenceT2C<F extends URIS2, L> {
     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]>
 }
 ```
 
@@ -193,6 +293,33 @@ export interface SequenceT3<F extends URIS3> {
     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]>
 }
 ```
 
@@ -218,6 +345,33 @@ export interface SequenceT3C<F extends URIS3, U, L> {
     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]>
 }
 ```
 
diff --git a/docs/modules/NonEmptyArray2v.ts.md b/docs/modules/NonEmptyArray2v.ts.md
new file mode 100644
index 00000000..424f6866
--- /dev/null
+++ b/docs/modules/NonEmptyArray2v.ts.md
@@ -0,0 +1,366 @@
+---
+title: NonEmptyArray2v.ts
+nav_order: 60
+parent: Modules
+---
+
+# Overview
+
+Data structure which represents non-empty arrays
+
+---
+
+<h2 class="text-delta">Table of contents</h2>
+
+- [NonEmptyArray (interface)](#nonemptyarray-interface)
+- [URI (type alias)](#uri-type-alias)
+- [URI (constant)](#uri-constant)
+- [nonEmptyArray (constant)](#nonemptyarray-constant)
+- [filter (function)](#filter-function)
+- [filterWithIndex (function)](#filterwithindex-function)
+- [findFirst (function)](#findfirst-function)
+- [findIndex (function)](#findindex-function)
+- [findLast (function)](#findlast-function)
+- [findLastIndex (function)](#findlastindex-function)
+- [fromArray (function)](#fromarray-function)
+- [fromNonEmptyArray (function)](#fromnonemptyarray-function)
+- [getSemigroup (function)](#getsemigroup-function)
+- [getSetoid (function)](#getsetoid-function)
+- [group (function)](#group-function)
+- [groupBy (function)](#groupby-function)
+- [groupSort (function)](#groupsort-function)
+- [head (function)](#head-function)
+- [insertAt (function)](#insertat-function)
+- [last (function)](#last-function)
+- [make (function)](#make-function)
+- [max (function)](#max-function)
+- [min (function)](#min-function)
+- [sort (function)](#sort-function)
+- [tail (function)](#tail-function)
+- [updateAt (function)](#updateat-function)
+
+---
+
+# NonEmptyArray (interface)
+
+**Signature**
+
+```ts
+export interface NonEmptyArray<A> extends Array<A> {
+  0: A
+  map: <B>(f: (a: A, index: number, nea: NonEmptyArray<A>) => B) => NonEmptyArray<B>
+  concat: (as: Array<A>) => NonEmptyArray<A>
+  reverse: () => NonEmptyArray<A>
+}
+```
+
+Added in v1.15.0
+
+# URI (type alias)
+
+**Signature**
+
+```ts
+export type URI = typeof URI
+```
+
+# URI (constant)
+
+**Signature**
+
+```ts
+export const URI = ...
+```
+
+# nonEmptyArray (constant)
+
+**Signature**
+
+```ts
+export const nonEmptyArray: Monad1<URI> &
+  Comonad1<URI> &
+  TraversableWithIndex1<URI, number> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number> = ...
+```
+
+Added in v1.15.0
+
+# filter (function)
+
+**Signature**
+
+```ts
+export function filter<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<NonEmptyArray<A>>
+export function filter<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.15.0
+
+# filterWithIndex (function)
+
+**Signature**
+
+```ts
+export function filterWithIndex<A>(
+  nea: NonEmptyArray<A>,
+  predicate: (i: number, a: A) => boolean
+): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.15.0
+
+# findFirst (function)
+
+**Signature**
+
+```ts
+export function findFirst<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<B>
+export function findFirst<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A> { ... }
+```
+
+Added in v1.15.0
+
+# findIndex (function)
+
+**Signature**
+
+```ts
+export function findIndex<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<number> { ... }
+```
+
+Added in v1.15.0
+
+# findLast (function)
+
+**Signature**
+
+```ts
+export function findLast<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<B>
+export function findLast<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A> { ... }
+```
+
+Added in v1.15.0
+
+# findLastIndex (function)
+
+**Signature**
+
+```ts
+export function findLastIndex<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<number> { ... }
+```
+
+Added in v1.15.0
+
+# fromArray (function)
+
+Builds a `NonEmptyArray` from an `Array` returning `none` if `as` is an empty array
+
+**Signature**
+
+```ts
+export function fromArray<A>(as: Array<A>): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.15.0
+
+# fromNonEmptyArray (function)
+
+Builds a `NonEmptyArray` from a provably (compile time) non empty `Array`.
+
+**Signature**
+
+```ts
+export function fromNonEmptyArray<A>(as: Array<A> & { 0: A }): NonEmptyArray<A> { ... }
+```
+
+Added in v1.15.0
+
+# getSemigroup (function)
+
+Builds a `Semigroup` instance for `NonEmptyArray`
+
+**Signature**
+
+```ts
+export const getSemigroup = <A = never>(): Semigroup<NonEmptyArray<A>> => ...
+```
+
+Added in v1.15.0
+
+# getSetoid (function)
+
+**Signature**
+
+```ts
+export function getSetoid<A>(S: Setoid<A>): Setoid<NonEmptyArray<A>> { ... }
+```
+
+**Example**
+
+```ts
+import { fromNonEmptyArray, getSetoid, make } from 'fp-ts/lib/NonEmptyArray2v'
+import { setoidNumber } from 'fp-ts/lib/Setoid'
+
+const S = getSetoid(setoidNumber)
+assert.strictEqual(S.equals(make(1, [2]), fromNonEmptyArray([1, 2])), true)
+assert.strictEqual(S.equals(make(1, [2]), fromNonEmptyArray([1, 3])), false)
+```
+
+Added in v1.15.0
+
+# group (function)
+
+Group equal, consecutive elements of an array into non empty arrays.
+
+**Signature**
+
+```ts
+export const group = <A>(S: Setoid<A>) => (as: Array<A>): Array<NonEmptyArray<A>> => ...
+```
+
+**Example**
+
+```ts
+import { make, group } from 'fp-ts/lib/NonEmptyArray2v'
+import { ordNumber } from 'fp-ts/lib/Ord'
+
+assert.deepStrictEqual(group(ordNumber)([1, 2, 1, 1]), [make(1, []), make(2, []), make(1, [1])])
+```
+
+Added in v1.15.0
+
+# groupBy (function)
+
+Splits an array into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning
+function on each element, and grouping the results according to values returned
+
+**Signature**
+
+```ts
+export const groupBy = <A>(as: Array<A>, f: (a: A) => string): { [key: string]: NonEmptyArray<A> } => ...
+```
+
+**Example**
+
+```ts
+import { make, groupBy } from 'fp-ts/lib/NonEmptyArray2v'
+
+assert.deepStrictEqual(groupBy(['foo', 'bar', 'foobar'], a => String(a.length)), {
+  '3': make('foo', ['bar']),
+  '6': make('foobar', [])
+})
+```
+
+Added in v1.15.0
+
+# groupSort (function)
+
+Sort and then group the elements of an array into non empty arrays.
+
+**Signature**
+
+```ts
+export const groupSort = <A>(O: Ord<A>): ((as: Array<A>) => Array<NonEmptyArray<A>>) => ...
+```
+
+**Example**
+
+```ts
+import { make, groupSort } from 'fp-ts/lib/NonEmptyArray2v'
+import { ordNumber } from 'fp-ts/lib/Ord'
+
+assert.deepStrictEqual(groupSort(ordNumber)([1, 2, 1, 1]), [make(1, [1, 1]), make(2, [])])
+```
+
+Added in v1.15.0
+
+# head (function)
+
+**Signature**
+
+```ts
+export function head<A>(nea: NonEmptyArray<A>): A { ... }
+```
+
+Added in v1.15.0
+
+# insertAt (function)
+
+**Signature**
+
+```ts
+export function insertAt<A>(i: number, a: A, nea: NonEmptyArray<A>): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.15.0
+
+# last (function)
+
+**Signature**
+
+```ts
+export function last<A>(nea: NonEmptyArray<A>): A { ... }
+```
+
+Added in v1.15.0
+
+# make (function)
+
+**Signature**
+
+```ts
+export function make<A>(head: A, tail: Array<A>): NonEmptyArray<A> { ... }
+```
+
+Added in v1.15.0
+
+# max (function)
+
+**Signature**
+
+```ts
+export function max<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A { ... }
+```
+
+Added in v1.15.0
+
+# min (function)
+
+**Signature**
+
+```ts
+export function min<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A { ... }
+```
+
+Added in v1.15.0
+
+# sort (function)
+
+**Signature**
+
+```ts
+export function sort<A>(O: Ord<A>): (nea: NonEmptyArray<A>) => NonEmptyArray<A> { ... }
+```
+
+Added in v1.15.0
+
+# tail (function)
+
+**Signature**
+
+```ts
+export function tail<A>(nea: NonEmptyArray<A>): Array<A> { ... }
+```
+
+Added in v1.15.0
+
+# updateAt (function)
+
+**Signature**
+
+```ts
+export function updateAt<A>(i: number, a: A, nea: NonEmptyArray<A>): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.15.0
diff --git a/docs/modules/Ord.ts.md b/docs/modules/Ord.ts.md
index b869174e..dd8da039 100644
--- a/docs/modules/Ord.ts.md
+++ b/docs/modules/Ord.ts.md
@@ -14,6 +14,8 @@ Instances should satisfy the laws of total orderings:
 2. Antisymmetry: if `S.compare(a, b) <= 0` and `S.compare(b, a) <= 0` then `a <-> b`
 3. Transitivity: if `S.compare(a, b) <= 0` and `S.compare(b, c) <= 0` then `S.compare(a, c) <= 0`
 
+See [Getting started with fp-ts: Ord](https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e)
+
 ---
 
 <h2 class="text-delta">Table of contents</h2>
diff --git a/docs/modules/Semigroup.ts.md b/docs/modules/Semigroup.ts.md
index 6978380b..4d79af48 100644
--- a/docs/modules/Semigroup.ts.md
+++ b/docs/modules/Semigroup.ts.md
@@ -4,6 +4,10 @@ nav_order: 73
 parent: Modules
 ---
 
+# Overview
+
+See [Getting started with fp-ts: Semigroup](https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7)
+
 ---
 
 <h2 class="text-delta">Table of contents</h2>
diff --git a/docs/modules/Setoid.ts.md b/docs/modules/Setoid.ts.md
index 62dbef68..30f5c82c 100644
--- a/docs/modules/Setoid.ts.md
+++ b/docs/modules/Setoid.ts.md
@@ -14,6 +14,8 @@ Instances must satisfy the following laws:
 2. Symmetry: `S.equals(a, b) === S.equals(b, a)`
 3. Transitivity: if `S.equals(a, b) === true` and `S.equals(b, c) === true`, then `S.equals(a, c) === true`
 
+See [Getting started with fp-ts: Setoid](https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3)
+
 ---
 
 <h2 class="text-delta">Table of contents</h2>
diff --git a/dtslint/ts3.0/index.ts b/dtslint/ts3.0/index.ts
index 1ca939fc..7c082dad 100644
--- a/dtslint/ts3.0/index.ts
+++ b/dtslint/ts3.0/index.ts
@@ -22,8 +22,10 @@ import * as Mon from '../../src/Monoid'
 import * as Se from '../../src/Setoid'
 import * as SM from '../../src/StrMap'
 import * as Fo from '../../src/Foldable'
+import * as Or from '../../src/Ord'
 
-const double = (n: number) => n * 2
+const double = (n: number): number => n * 2
+const len = (s: string): number => s.length
 
 //
 // Functor
@@ -253,3 +255,29 @@ const Mon4 = Mon.getDictionaryMonoid<Keys, number>(S.semigroupSum) // $ExpectTyp
 //
 
 const toUnfoldable3 = SM.toUnfoldable(A.array)(new SM.StrMap({ a: 1 })) // $ExpectType [string, number][]
+
+//
+// NonEmptyArray2v
+//
+
+import * as NEA2v from '../../src/NonEmptyArray2v'
+
+declare const nea2v1: NEA2v.NonEmptyArray<string>
+declare const nea2v2: NEA2v.NonEmptyArray<string>
+declare const array1: Array<string>
+
+const nea2v1make1 = NEA2v.make<number>(1, []) // $ExpectType NonEmptyArray<number>
+
+const nea2vValid = NEA2v.fromNonEmptyArray([1]) // $ExpectType NonEmptyArray<number>
+// $ExpectError
+const nea2vInvalid = NEA2v.fromNonEmptyArray([])
+
+const nea2v1map1 = nea2v1.map(len) // $ExpectType NonEmptyArray<number>
+
+const nea2v1concat1 = nea2v1.concat(nea2v2) // $ExpectType NonEmptyArray<string>
+const nea2v1concat2 = nea2v1.concat(array1) // $ExpectType NonEmptyArray<string>
+const nea2v1concat3 = array1.concat(nea2v1) // $ExpectType string[]
+
+const nea2v1sort1 = nea2v1.sort(Or.ordString.compare) // $ExpectType NonEmptyArray<string>
+
+const nea2v1reverse1 = nea2v1.reverse() // $ExpectType NonEmptyArray<string>
diff --git a/package.json b/package.json
index d1affed3..62bbea12 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "1.14.3",
+  "version": "1.14.4",
   "description": "Functional programming in TypeScript",
   "files": [
     "lib"
@@ -17,7 +17,7 @@
     "clean": "rimraf lib/*",
     "build": "npm run clean && tsc",
     "prepublish": "npm run build",
-    "doctoc": "doctoc README.md code-conventions.md docs --title \"**Table of contents**\"",
+    "doctoc": "doctoc README.md code-conventions.md --title \"**Table of contents**\"",
     "mocha": "mocha -r ts-node/register test/*.ts",
     "dtslint": "dtslint dtslint",
     "docs": "docs-ts"
diff --git a/src/Apply.ts b/src/Apply.ts
index 274bb771..c257225f 100644
--- a/src/Apply.ts
+++ b/src/Apply.ts
@@ -248,6 +248,33 @@ export interface SequenceT3<F extends URIS3> {
     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]>
@@ -266,6 +293,33 @@ export interface SequenceT3C<F extends URIS3, U, L> {
     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]>
@@ -279,6 +333,33 @@ export interface SequenceT2<F extends URIS2> {
     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]>
@@ -290,6 +371,33 @@ export interface SequenceT2C<F extends URIS2, L> {
     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]>
@@ -297,6 +405,29 @@ export interface SequenceT1<F extends URIS> {
   <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]>
@@ -304,6 +435,29 @@ export interface SequenceT<F> {
   <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> } = {}
diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts
index 0c1d3777..38bbb70c 100644
--- a/src/NonEmptyArray.ts
+++ b/src/NonEmptyArray.ts
@@ -4,29 +4,27 @@
 import { Applicative } from './Applicative'
 import {
   array,
-  last,
-  sort,
-  lookup,
   findFirst as arrayFindFirst,
   findIndex as arrayFindIndex,
-  insertAt as arrayInsertAt,
-  updateAt as arrayUpdateAt,
   findLast as arrayFindLast,
-  findLastIndex as arrayFindLastIndex
+  findLastIndex as arrayFindLastIndex,
+  insertAt as arrayInsertAt,
+  last,
+  lookup,
+  sort,
+  updateAt as arrayUpdateAt
 } from './Array'
-
 import { Comonad1 } from './Comonad'
-import { Foldable2v1 } from './Foldable2v'
-import { compose, toString, Refinement, Predicate } from './function'
+import { FoldableWithIndex1 } from './FoldableWithIndex'
+import { compose, Predicate, Refinement, toString } from './function'
+import { FunctorWithIndex1 } from './FunctorWithIndex'
 import { HKT } from './HKT'
 import { Monad1 } from './Monad'
 import { Monoid } from './Monoid'
 import { none, Option, some } from './Option'
 import { Ord } from './Ord'
 import { fold, getJoinSemigroup, getMeetSemigroup, Semigroup } from './Semigroup'
-import { Setoid, getArraySetoid, fromEquals } from './Setoid'
-import { FunctorWithIndex1 } from './FunctorWithIndex'
-import { FoldableWithIndex1 } from './FoldableWithIndex'
+import { fromEquals, getArraySetoid, Setoid } from './Setoid'
 import { TraversableWithIndex1 } from './TraversableWithIndex'
 
 declare module './HKT' {
@@ -317,6 +315,7 @@ export class NonEmptyArray<A> {
   }
 
   /**
+   * Use `lookup` instead
    * @since 1.11.0
    * @deprecated
    */
@@ -335,7 +334,7 @@ export class NonEmptyArray<A> {
    *
    * @since 1.11.0
    */
-  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>
   findFirst(predicate: Predicate<A>): Option<A> {
     return predicate(this.head) ? some(this.head) : arrayFindFirst(this.tail, predicate)
@@ -482,7 +481,7 @@ const unsafeFromArray = <A>(as: Array<A>): NonEmptyArray<A> => {
 }
 
 /**
- * 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
  *
  * @since 1.0.0
  */
@@ -515,7 +514,7 @@ const concat = <A>(fx: NonEmptyArray<A>, fy: NonEmptyArray<A>): NonEmptyArray<A>
 }
 
 /**
- * Builds `Semigroup` instance for `NonEmptyArray` of specified type arument
+ * Builds a `Semigroup` instance for `NonEmptyArray`
  *
  * @since 1.0.0
  */
@@ -524,7 +523,6 @@ export const getSemigroup = <A = never>(): Semigroup<NonEmptyArray<A>> => {
 }
 
 /**
- *
  * @example
  * import { NonEmptyArray, getSetoid } from 'fp-ts/lib/NonEmptyArray'
  * import { setoidNumber } from 'fp-ts/lib/Setoid'
@@ -683,7 +681,6 @@ const traverseWithIndex = <F>(
  */
 export const nonEmptyArray: Monad1<URI> &
   Comonad1<URI> &
-  Foldable2v1<URI> &
   TraversableWithIndex1<URI, number> &
   FunctorWithIndex1<URI, number> &
   FoldableWithIndex1<URI, number> = {
diff --git a/src/NonEmptyArray2v.ts b/src/NonEmptyArray2v.ts
new file mode 100644
index 00000000..5f2190a9
--- /dev/null
+++ b/src/NonEmptyArray2v.ts
@@ -0,0 +1,309 @@
+/**
+ * @file Data structure which represents non-empty arrays
+ */
+import { Monad1 } from './Monad'
+import * as A from './Array'
+import { Comonad1 } from './Comonad'
+import { FunctorWithIndex1 } from './FunctorWithIndex'
+import { TraversableWithIndex1, TraverseWithIndex1 } from './TraversableWithIndex'
+import { FoldableWithIndex1 } from './FoldableWithIndex'
+import { Ord } from './Ord'
+import { getMeetSemigroup, getJoinSemigroup, Semigroup } from './Semigroup'
+import { Option, some, none } from './Option'
+import { Setoid } from './Setoid'
+import { compose, Predicate, Refinement } from './function'
+import { Traverse1 } from './Traversable'
+import { Sequence1 } from './Traversable2v'
+
+declare module './HKT' {
+  interface URI2HKT<A> {
+    NonEmptyArray2v: NonEmptyArray<A>
+  }
+}
+
+export const URI = 'NonEmptyArray2v'
+
+export type URI = typeof URI
+
+/**
+ * @since 1.15.0
+ */
+export interface NonEmptyArray<A> extends Array<A> {
+  0: A
+  map: <B>(f: (a: A, index: number, nea: NonEmptyArray<A>) => B) => NonEmptyArray<B>
+  concat: (as: Array<A>) => NonEmptyArray<A>
+  reverse: () => NonEmptyArray<A>
+}
+
+/**
+ * @since 1.15.0
+ */
+export function make<A>(head: A, tail: Array<A>): NonEmptyArray<A> {
+  return [head, ...tail] as any
+}
+
+/**
+ * @since 1.15.0
+ */
+export function head<A>(nea: NonEmptyArray<A>): A {
+  return nea[0]
+}
+
+/**
+ * @since 1.15.0
+ */
+export function tail<A>(nea: NonEmptyArray<A>): Array<A> {
+  return nea.slice(1)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function min<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A {
+  const S = getMeetSemigroup(ord)
+  return nea => nea.reduce(S.concat)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function max<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A {
+  const S = getJoinSemigroup(ord)
+  return nea => nea.reduce(S.concat)
+}
+
+/**
+ * Builds a `NonEmptyArray` from an `Array` returning `none` if `as` is an empty array
+ *
+ * @since 1.15.0
+ */
+export function fromArray<A>(as: Array<A>): Option<NonEmptyArray<A>> {
+  return as.length > 0 ? some(as as any) : none
+}
+
+/**
+ * Builds a `NonEmptyArray` from a provably (compile time) non empty `Array`.
+ *
+ * @since 1.15.0
+ */
+export function fromNonEmptyArray<A>(as: Array<A> & { 0: A }): NonEmptyArray<A> {
+  return as as any
+}
+
+/**
+ * Builds a `Semigroup` instance for `NonEmptyArray`
+ *
+ * @since 1.15.0
+ */
+export const getSemigroup = <A = never>(): Semigroup<NonEmptyArray<A>> => {
+  return {
+    concat: (x, y) => x.concat(y)
+  }
+}
+
+/**
+ * @example
+ * import { fromNonEmptyArray, getSetoid, make } from 'fp-ts/lib/NonEmptyArray2v'
+ * import { setoidNumber } from 'fp-ts/lib/Setoid'
+ *
+ * const S = getSetoid(setoidNumber)
+ * assert.strictEqual(S.equals(make(1, [2]), fromNonEmptyArray([1, 2])), true)
+ * assert.strictEqual(S.equals(make(1, [2]), fromNonEmptyArray([1, 3])), false)
+ *
+ * @since 1.15.0
+ */
+export function getSetoid<A>(S: Setoid<A>): Setoid<NonEmptyArray<A>> {
+  return A.getSetoid(S)
+}
+
+/**
+ * Group equal, consecutive elements of an array into non empty arrays.
+ *
+ * @example
+ * import { make, group } from 'fp-ts/lib/NonEmptyArray2v'
+ * import { ordNumber } from 'fp-ts/lib/Ord'
+ *
+ * assert.deepStrictEqual(group(ordNumber)([1, 2, 1, 1]), [
+ *   make(1, []),
+ *   make(2, []),
+ *   make(1, [1])
+ * ])
+ *
+ * @since 1.15.0
+ */
+export const group = <A>(S: Setoid<A>) => (as: Array<A>): Array<NonEmptyArray<A>> => {
+  const len = as.length
+  if (len === 0) {
+    return A.empty
+  }
+  const r: Array<NonEmptyArray<A>> = []
+  let head: A = as[0]
+  let nea = fromNonEmptyArray([head])
+  for (let i = 1; i < len; i++) {
+    const x = as[i]
+    if (S.equals(x, head)) {
+      nea.push(x)
+    } else {
+      r.push(nea)
+      head = x
+      nea = fromNonEmptyArray([head])
+    }
+  }
+  r.push(nea)
+  return r
+}
+
+/**
+ * Sort and then group the elements of an array into non empty arrays.
+ *
+ * @example
+ * import { make, groupSort } from 'fp-ts/lib/NonEmptyArray2v'
+ * import { ordNumber } from 'fp-ts/lib/Ord'
+ *
+ * assert.deepStrictEqual(groupSort(ordNumber)([1, 2, 1, 1]), [make(1, [1, 1]), make(2, [])])
+ *
+ * @since 1.15.0
+ */
+export const groupSort = <A>(O: Ord<A>): ((as: Array<A>) => Array<NonEmptyArray<A>>) => {
+  return compose(
+    group(O),
+    A.sort(O)
+  )
+}
+
+/**
+ * Splits an array into sub-non-empty-arrays stored in an object, based on the result of calling a `string`-returning
+ * function on each element, and grouping the results according to values returned
+ *
+ * @example
+ * import { make, groupBy } from 'fp-ts/lib/NonEmptyArray2v'
+ *
+ * assert.deepStrictEqual(groupBy(['foo', 'bar', 'foobar'], a => String(a.length)), {
+ *   '3': make('foo', ['bar']),
+ *   '6': make('foobar', [])
+ * })
+ *
+ * @since 1.15.0
+ */
+export const groupBy = <A>(as: Array<A>, f: (a: A) => string): { [key: string]: NonEmptyArray<A> } => {
+  const r: { [key: string]: NonEmptyArray<A> } = {}
+  for (const a of as) {
+    const k = f(a)
+    if (r.hasOwnProperty(k)) {
+      r[k].push(a)
+    } else {
+      r[k] = make(a, [])
+    }
+  }
+  return r
+}
+
+/**
+ * @since 1.15.0
+ */
+export function last<A>(nea: NonEmptyArray<A>): A {
+  return nea[nea.length - 1]
+}
+
+/**
+ * @since 1.15.0
+ */
+export function sort<A>(O: Ord<A>): (nea: NonEmptyArray<A>) => NonEmptyArray<A> {
+  return A.sort(O) as any
+}
+
+/**
+ * @since 1.15.0
+ */
+export function findFirst<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<B>
+export function findFirst<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A>
+export function findFirst<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A> {
+  return A.findFirst(nea, predicate)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function findLast<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<B>
+export function findLast<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A>
+export function findLast<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<A> {
+  return A.findLast(nea, predicate)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function findIndex<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<number> {
+  return A.findIndex(nea, predicate)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function findLastIndex<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<number> {
+  return A.findLastIndex(nea, predicate)
+}
+
+/**
+ * @since 1.15.0
+ */
+export function insertAt<A>(i: number, a: A, nea: NonEmptyArray<A>): Option<NonEmptyArray<A>> {
+  return A.insertAt(i, a, nea) as any
+}
+
+/**
+ * @since 1.15.0
+ */
+export function updateAt<A>(i: number, a: A, nea: NonEmptyArray<A>): Option<NonEmptyArray<A>> {
+  return A.updateAt(i, a, nea) as any
+}
+
+/**
+ * @since 1.15.0
+ */
+export function filter<A, B extends A>(nea: NonEmptyArray<A>, refinement: Refinement<A, B>): Option<NonEmptyArray<A>>
+export function filter<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<NonEmptyArray<A>>
+export function filter<A>(nea: NonEmptyArray<A>, predicate: Predicate<A>): Option<NonEmptyArray<A>> {
+  return filterWithIndex(nea, (_, a) => predicate(a))
+}
+
+/**
+ * @since 1.15.0
+ */
+export function filterWithIndex<A>(
+  nea: NonEmptyArray<A>,
+  predicate: (i: number, a: A) => boolean
+): Option<NonEmptyArray<A>> {
+  return fromArray(nea.filter((a, i) => predicate(i, a)))
+}
+
+const mapWithIndex = <A, B>(fa: NonEmptyArray<A>, f: (i: number, a: A) => B): NonEmptyArray<B> => {
+  return fa.map((a, i) => f(i, a))
+}
+
+/**
+ * @since 1.15.0
+ */
+export const nonEmptyArray: Monad1<URI> &
+  Comonad1<URI> &
+  TraversableWithIndex1<URI, number> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number> = {
+  URI,
+  map: A.array.map as <A, B>(fa: NonEmptyArray<A>, f: (a: A) => B) => any,
+  mapWithIndex,
+  of: A.array.of as <A>(a: A) => NonEmptyArray<A>,
+  ap: A.array.ap as <A, B>(fab: NonEmptyArray<(a: A) => B>, fa: NonEmptyArray<A>) => any,
+  chain: A.array.chain as <A, B>(fa: NonEmptyArray<A>, f: (a: A) => NonEmptyArray<B>) => any,
+  extend: A.array.extend as <A, B>(ea: any, f: (fa: NonEmptyArray<A>) => B) => NonEmptyArray<B>,
+  extract: head,
+  reduce: A.array.reduce,
+  foldMap: A.array.foldMap,
+  foldr: A.array.foldr,
+  traverse: A.array.traverse as Traverse1<any>,
+  sequence: A.array.sequence as Sequence1<any>,
+  reduceWithIndex: A.array.reduceWithIndex,
+  foldMapWithIndex: A.array.foldMapWithIndex,
+  foldrWithIndex: A.array.foldrWithIndex,
+  traverseWithIndex: A.array.traverseWithIndex as TraverseWithIndex1<any, number>
+}
diff --git a/src/Ord.ts b/src/Ord.ts
index 31025bbd..001ffe6c 100644
--- a/src/Ord.ts
+++ b/src/Ord.ts
@@ -6,6 +6,8 @@
  * 1. Reflexivity: `S.compare(a, a) <= 0`
  * 2. Antisymmetry: if `S.compare(a, b) <= 0` and `S.compare(b, a) <= 0` then `a <-> b`
  * 3. Transitivity: if `S.compare(a, b) <= 0` and `S.compare(b, c) <= 0` then `S.compare(a, c) <= 0`
+ *
+ * See [Getting started with fp-ts: Ord](https://dev.to/gcanti/getting-started-with-fp-ts-ord-5f1e)
  */
 import { Ordering, semigroupOrdering } from './Ordering'
 import { Semigroup } from './Semigroup'
diff --git a/src/Semigroup.ts b/src/Semigroup.ts
index e2829def..e398c59c 100644
--- a/src/Semigroup.ts
+++ b/src/Semigroup.ts
@@ -1,3 +1,6 @@
+/**
+ * @file See [Getting started with fp-ts: Semigroup](https://dev.to/gcanti/getting-started-with-fp-ts-semigroup-2mf7)
+ */
 import { Ord, max, min } from './Ord'
 import { concat, identity } from './function'
 
diff --git a/src/Setoid.ts b/src/Setoid.ts
index af522290..25a689b4 100644
--- a/src/Setoid.ts
+++ b/src/Setoid.ts
@@ -6,6 +6,8 @@
  * 1. Reflexivity: `S.equals(a, a) === true`
  * 2. Symmetry: `S.equals(a, b) === S.equals(b, a)`
  * 3. Transitivity: if `S.equals(a, b) === true` and `S.equals(b, c) === true`, then `S.equals(a, c) === true`
+ *
+ * See [Getting started with fp-ts: Setoid](https://dev.to/gcanti/getting-started-with-fp-ts-setoid-39f3)
  */
 
 /**
diff --git a/src/index.ts b/src/index.ts
index c655b2ae..e148ab73 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -112,6 +112,8 @@ import * as monoidal from './Monoidal'
 export { monoidal }
 import * as nonEmptyArray from './NonEmptyArray'
 export { nonEmptyArray }
+import * as nonEmptyArray2v from './NonEmptyArray2v'
+export { nonEmptyArray2v }
 import * as option from './Option'
 export { option }
 import * as optionT from './OptionT'
diff --git a/tslint.json b/tslint.json
index e44e782f..49a3de1e 100644
--- a/tslint.json
+++ b/tslint.json
@@ -10,6 +10,7 @@
     "forin": true,
     "no-console": true,
     "array-type": [true, "generic"],
-    "deprecation": true
+    "deprecation": true,
+    "no-inferred-empty-object-type": true
   }
 }


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index d7b1d532..144f67ff 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -711,10 +711,10 @@ describe('Array', () => {
 
     // FoldableWithIndex compatibility
     const M = monoidString
-    const f = (i: number, s: string) => s + i
+    const f = (i: number, s: string): string => s + i
     assert.deepStrictEqual(
       array.foldMapWithIndex(M)(ta, f),
-      array.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const(f(i, a))).value
+      array.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const<string, unknown>(f(i, a))).value
     )
 
     // FunctorWithIndex compatibility
diff --git a/test/Const.ts b/test/Const.ts
index 8c4cbce4..fd73ad31 100644
--- a/test/Const.ts
+++ b/test/Const.ts
@@ -44,6 +44,6 @@ describe('Const', () => {
   it('getApplicative', () => {
     const F = getApply(semigroupString)
     const fa = new Const<string, (n: number) => number>('foo')
-    assert.deepStrictEqual(F.ap(fa, new Const('bar')), new Const('foobar'))
+    assert.deepStrictEqual(F.ap(fa, new Const('bar')), new Const<string, unknown>('foobar'))
   })
 })
diff --git a/test/Either.ts b/test/Either.ts
index 72317229..0444e002 100644
--- a/test/Either.ts
+++ b/test/Either.ts
@@ -149,13 +149,13 @@ describe('Either', () => {
 
   it('getOrElse', () => {
     assert.deepStrictEqual(right(12).getOrElse(17), 12)
-    assert.deepStrictEqual(left(12).getOrElse(17), 17)
+    assert.deepStrictEqual(left<string, number>('a').getOrElse(17), 17)
   })
 
   it('getOrElseL', () => {
     assert.deepStrictEqual(right(12).getOrElseL(() => 17), 12)
-    assert.deepStrictEqual(left(12).getOrElseL(() => 17), 17)
-    assert.deepStrictEqual(left(12).getOrElseL((l: number) => l + 1), 13)
+    assert.deepStrictEqual(left<string, number>('a').getOrElseL(() => 17), 17)
+    assert.deepStrictEqual(left<string, number>('a').getOrElseL((l: string) => l.length + 1), 2)
   })
 
   it('fromOption', () => {
diff --git a/test/FreeGroup.ts b/test/FreeGroup.ts
index b4153d26..d3ee75ce 100644
--- a/test/FreeGroup.ts
+++ b/test/FreeGroup.ts
@@ -32,7 +32,7 @@ describe('FreeGroup', () => {
   })
 
   it('of', () => {
-    assert.deepStrictEqual(freeGroup.of(1), new FreeGroup([right(1)]))
+    assert.deepStrictEqual(freeGroup.of(1), new FreeGroup([right<number, number>(1)]))
   })
 
   it('map', () => {
@@ -48,14 +48,14 @@ describe('FreeGroup', () => {
     assert.deepStrictEqual(
       freeGroup.ap(fab, fa),
       new FreeGroup([
-        left(false),
-        right(false),
-        left(true),
-        right(true),
-        left(true),
-        right(true),
-        left(false),
-        right(false)
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false)
       ])
     )
     assert.deepStrictEqual(fab.ap_(fa), fa.ap(fab))
@@ -63,26 +63,32 @@ describe('FreeGroup', () => {
 
   it('chain', () => {
     const fa = new FreeGroup<number>([left(1), right(1), left(2), right(2)])
-    const f = (n: number) => new FreeGroup([left(n > 1), right(n > 1), left(n < 2), right(n < 2)])
+    const f = (n: number) =>
+      new FreeGroup([
+        left<boolean, boolean>(n > 1),
+        right<boolean, boolean>(n > 1),
+        left<boolean, boolean>(n < 2),
+        right<boolean, boolean>(n < 2)
+      ])
     assert.deepStrictEqual(
       freeGroup.chain(fa, f),
       new FreeGroup([
-        left(false),
-        right(false),
-        left(true),
-        right(true),
-        left(false),
-        right(false),
-        left(true),
-        right(true),
-        left(true),
-        right(true),
-        left(false),
-        right(false),
-        left(true),
-        right(true),
-        left(false),
-        right(false)
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false),
+        left<boolean, boolean>(true),
+        right<boolean, boolean>(true),
+        left<boolean, boolean>(false),
+        right<boolean, boolean>(false)
       ])
     )
   })
diff --git a/test/NonEmptyArray.ts b/test/NonEmptyArray.ts
index b38dea06..5cb54c25 100644
--- a/test/NonEmptyArray.ts
+++ b/test/NonEmptyArray.ts
@@ -40,7 +40,7 @@ describe('NonEmptyArray', () => {
     assert.deepStrictEqual(nonEmptyArray.mapWithIndex(x, add).toArray(), [1, 3])
   })
 
-  it('ap', () => {
+  it('of', () => {
     assert.deepStrictEqual(nonEmptyArray.of(1), new NonEmptyArray(1, []))
   })
 
@@ -93,7 +93,7 @@ describe('NonEmptyArray', () => {
   })
 
   it('min', () => {
-    assert.deepStrictEqual(new NonEmptyArray(1, [2, 3]).min(ordNumber), 1)
+    assert.deepStrictEqual(new NonEmptyArray(2, [1, 3]).min(ordNumber), 1)
     assert.deepStrictEqual(new NonEmptyArray(3, []).min(ordNumber), 3)
   })
 
@@ -367,10 +367,10 @@ describe('NonEmptyArray', () => {
 
     // FoldableWithIndex compatibility
     const M = monoidString
-    const f = (i: number, s: string) => s + i
+    const f = (i: number, s: string): string => s + i
     assert.deepStrictEqual(
       nonEmptyArray.foldMapWithIndex(M)(ta, f),
-      nonEmptyArray.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const(f(i, a))).value
+      nonEmptyArray.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const<string, unknown>(f(i, a))).value
     )
 
     // FunctorWithIndex compatibility
diff --git a/test/NonEmptyArray2v.ts b/test/NonEmptyArray2v.ts
new file mode 100644
index 00000000..dc47c52a
--- /dev/null
+++ b/test/NonEmptyArray2v.ts
@@ -0,0 +1,382 @@
+import * as assert from 'assert'
+import { fold, monoidSum, monoidString } from '../src/Monoid'
+import {
+  nonEmptyArray,
+  make,
+  head,
+  tail,
+  min,
+  max,
+  fromArray,
+  getSemigroup,
+  getSetoid,
+  group,
+  groupSort,
+  groupBy,
+  last,
+  sort,
+  findFirst,
+  findLast,
+  findIndex,
+  findLastIndex,
+  insertAt,
+  updateAt,
+  filter,
+  filterWithIndex,
+  fromNonEmptyArray
+} from '../src/NonEmptyArray2v'
+import { none, option, some, isSome } from '../src/Option'
+import { ordNumber } from '../src/Ord'
+import * as F from '../src/Foldable'
+import { identity } from '../src/function'
+import * as T from '../src/Traversable'
+import * as I from '../src/Identity'
+import * as C from '../src/Const'
+import { setoidNumber } from '../src/Setoid'
+
+describe.only('NonEmptyArray2v', () => {
+  it('make', () => {
+    assert.deepStrictEqual(make(1, [2]), fromNonEmptyArray([1, 2]))
+  })
+
+  it('head', () => {
+    const x = fromNonEmptyArray([1, 2])
+    assert.deepStrictEqual(head(x), 1)
+  })
+
+  it('tail', () => {
+    const x = fromNonEmptyArray([1, 2])
+    assert.deepStrictEqual(tail(x), [2])
+  })
+
+  it('concat', () => {
+    const x = fromNonEmptyArray([1, 2])
+    const y = fromNonEmptyArray([3, 4])
+    assert.deepStrictEqual(x.concat(y), [1, 2, 3, 4])
+  })
+
+  it('map', () => {
+    const x = fromNonEmptyArray([1, 2])
+    const double = (n: number) => n * 2
+    assert.deepStrictEqual(nonEmptyArray.map(x, double), [2, 4])
+  })
+
+  it('mapWithIndex', () => {
+    const x = fromNonEmptyArray([1, 2])
+    const add = (i: number, n: number) => n + i
+    assert.deepStrictEqual(nonEmptyArray.mapWithIndex(x, add), [1, 3])
+  })
+
+  it('of', () => {
+    assert.deepStrictEqual(nonEmptyArray.of(1), fromNonEmptyArray([1]))
+  })
+
+  it('ap', () => {
+    const x = fromNonEmptyArray([1, 2])
+    const double = (n: number) => n * 2
+    assert.deepStrictEqual(nonEmptyArray.ap(fromNonEmptyArray([double, double]), x), [2, 4, 2, 4])
+  })
+
+  it('chain', () => {
+    const x = fromNonEmptyArray([1, 2])
+    const f = (a: number) => fromNonEmptyArray([a, 4])
+    assert.deepStrictEqual(nonEmptyArray.chain(x, f), [1, 4, 2, 4])
+  })
+
+  it('extend', () => {
+    const sum = fold(monoidSum)
+    assert.deepStrictEqual(nonEmptyArray.extend(fromNonEmptyArray([1, 2, 3, 4]), sum), fromNonEmptyArray([10, 9, 7, 4]))
+  })
+
+  it('extract', () => {
+    assert.strictEqual(nonEmptyArray.extract(fromNonEmptyArray([1, 2, 3])), 1)
+  })
+
+  it('traverse', () => {
+    assert.deepStrictEqual(
+      nonEmptyArray.traverse(option)(fromNonEmptyArray([1, 2, 3]), n => (n >= 0 ? some(n) : none)),
+      some(fromNonEmptyArray([1, 2, 3]))
+    )
+    assert.deepStrictEqual(
+      nonEmptyArray.traverse(option)(fromNonEmptyArray([1, 2, 3]), n => (n >= 2 ? some(n) : none)),
+      none
+    )
+  })
+
+  it('sequence', () => {
+    const old = T.sequence(option, nonEmptyArray)
+    const sequence = nonEmptyArray.sequence(option)
+    const x1 = fromNonEmptyArray([some(1), some(2), some(3)])
+    assert.deepStrictEqual(sequence(x1), some(fromNonEmptyArray([1, 2, 3])))
+    assert.deepStrictEqual(sequence(x1), old(x1))
+    const x2 = fromNonEmptyArray([none, some(2), some(3)])
+    assert.deepStrictEqual(sequence(x2), none)
+    assert.deepStrictEqual(sequence(x2), old(x2))
+  })
+
+  it('min', () => {
+    assert.deepStrictEqual(min(ordNumber)(fromNonEmptyArray([2, 1, 3])), 1)
+    assert.deepStrictEqual(min(ordNumber)(fromNonEmptyArray<number>([3])), 3)
+  })
+
+  it('max', () => {
+    assert.deepStrictEqual(max(ordNumber)(fromNonEmptyArray([1, 2, 3])), 3)
+    assert.deepStrictEqual(max(ordNumber)(fromNonEmptyArray<number>([1])), 1)
+  })
+
+  it('reduce', () => {
+    const x = fromNonEmptyArray(['a', 'b'])
+    assert.strictEqual(nonEmptyArray.reduce(x, '', (b, a) => b + a), 'ab')
+  })
+
+  it('foldMap', () => {
+    const old = F.foldMap(nonEmptyArray, monoidString)
+    const foldMap = nonEmptyArray.foldMap(monoidString)
+    const x1 = fromNonEmptyArray(['a', 'b', 'c'])
+    const f1 = identity
+    assert.strictEqual(foldMap(x1, f1), 'abc')
+    assert.strictEqual(foldMap(x1, f1), old(x1, f1))
+  })
+
+  it('foldr', () => {
+    const old = F.foldr(nonEmptyArray)
+    const foldr = nonEmptyArray.foldr
+    const x1 = fromNonEmptyArray(['a', 'b', 'c'])
+    const init1 = ''
+    const f1 = (a: string, acc: string) => acc + a
+    assert.strictEqual(foldr(x1, init1, f1), 'cba')
+    assert.strictEqual(foldr(x1, init1, f1), old(x1, init1, f1))
+  })
+
+  it('fromArray', () => {
+    assert.deepStrictEqual(fromArray([]), none)
+    assert.deepStrictEqual(fromArray([1]), some(fromNonEmptyArray([1])))
+    assert.deepStrictEqual(fromArray([1, 2]), some(fromNonEmptyArray([1, 2])))
+  })
+
+  it('getSemigroup', () => {
+    const S = getSemigroup<number>()
+    assert.deepStrictEqual(
+      S.concat(fromNonEmptyArray<number>([1]), fromNonEmptyArray<number>([2])),
+      fromNonEmptyArray([1, 2])
+    )
+    assert.deepStrictEqual(
+      S.concat(fromNonEmptyArray([1, 2]), fromNonEmptyArray([3, 4])),
+      fromNonEmptyArray([1, 2, 3, 4])
+    )
+  })
+
+  it('getSetoid', () => {
+    const S = getSetoid(setoidNumber)
+    assert.strictEqual(S.equals(fromNonEmptyArray<number>([1]), fromNonEmptyArray<number>([1])), true)
+    assert.strictEqual(S.equals(fromNonEmptyArray<number>([1]), fromNonEmptyArray([1, 2])), false)
+  })
+
+  it('group', () => {
+    assert.deepStrictEqual(group(ordNumber)([]), [])
+
+    assert.deepStrictEqual(group(ordNumber)([1, 2, 1, 1]), [
+      fromNonEmptyArray([1]),
+      fromNonEmptyArray([2]),
+      fromNonEmptyArray([1, 1])
+    ])
+
+    assert.deepStrictEqual(group(ordNumber)([1, 2, 1, 1, 3]), [
+      fromNonEmptyArray([1]),
+      fromNonEmptyArray([2]),
+      fromNonEmptyArray([1, 1]),
+      fromNonEmptyArray([3])
+    ])
+  })
+
+  it('groupSort', () => {
+    assert.deepStrictEqual(groupSort(ordNumber)([]), [])
+    assert.deepStrictEqual(groupSort(ordNumber)([1, 2, 1, 1]), [fromNonEmptyArray([1, 1, 1]), fromNonEmptyArray([2])])
+  })
+
+  it('last', () => {
+    assert.deepStrictEqual(last(fromNonEmptyArray([1, 2, 3])), 3)
+    assert.deepStrictEqual(last(fromNonEmptyArray([1])), 1)
+  })
+
+  it('sort', () => {
+    assert.deepStrictEqual(sort(ordNumber)(fromNonEmptyArray([3, 2, 1])), fromNonEmptyArray([1, 2, 3]))
+  })
+
+  it('reverse', () => {
+    const result = fromNonEmptyArray([1, 2, 3]).reverse()
+    const expected = fromNonEmptyArray([3, 2, 1])
+    assert.deepStrictEqual(result, expected)
+  })
+
+  it('groupBy', () => {
+    assert.deepStrictEqual(groupBy([], _ => ''), {})
+    assert.deepStrictEqual(groupBy([1], String), { '1': fromNonEmptyArray([1]) })
+    assert.deepStrictEqual(groupBy(['foo', 'bar', 'foobar'], a => String(a.length)), {
+      '3': fromNonEmptyArray(['foo', 'bar']),
+      '6': fromNonEmptyArray(['foobar'])
+    })
+  })
+
+  it('findFirst', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(findFirst(arr, ({ x }) => x === 1).map(x => x === a1), some(true))
+    assert.deepStrictEqual(findFirst(arr, ({ x }) => x === 2), some(a3))
+    assert.deepStrictEqual(findFirst(arr, ({ x }) => x === 10), none)
+  })
+
+  it('findLast', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(findLast(arr, ({ x }) => x === 1).map(x => x === a2), some(true))
+    assert.deepStrictEqual(findLast(arr, ({ x }) => x === 2), some(a3))
+    assert.deepStrictEqual(findLast(arr, ({ x }) => x === 10), none)
+  })
+
+  it('findIndex', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(findIndex(arr, ({ x }) => x === 1), some(0))
+    assert.deepStrictEqual(findIndex(arr, ({ x }) => x === 2), some(2))
+    assert.deepStrictEqual(findIndex(arr, ({ x }) => x === 10), none)
+  })
+
+  it('findLastIndex', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(findLastIndex(arr, ({ x }) => x === 1), some(1))
+    assert.deepStrictEqual(findLastIndex(arr, ({ x }) => x === 2), some(2))
+    assert.deepStrictEqual(findLastIndex(arr, ({ x }) => x === 10), none)
+  })
+
+  it('insertAt', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const a4 = make2(3)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(insertAt(0, a4, arr), some(fromNonEmptyArray([a4, a1, a2, a3])))
+    assert.deepStrictEqual(insertAt(-1, a4, arr), none)
+    assert.deepStrictEqual(insertAt(3, a4, arr), some(fromNonEmptyArray([a1, a2, a3, a4])))
+    assert.deepStrictEqual(insertAt(1, a4, arr), some(fromNonEmptyArray([a1, a4, a2, a3])))
+    assert.deepStrictEqual(insertAt(4, a4, arr), none)
+  })
+
+  it('updateAt', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const a4 = make2(3)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(updateAt(0, a4, arr), some(fromNonEmptyArray([a4, a2, a3])))
+    assert.deepStrictEqual(updateAt(-1, a4, arr), none)
+    assert.deepStrictEqual(updateAt(3, a4, arr), none)
+    assert.deepStrictEqual(updateAt(1, a4, arr), some(fromNonEmptyArray([a1, a4, a3])))
+    // should return the same reference if nothing changed
+    const r1 = updateAt(0, a1, arr)
+    if (r1.isSome()) {
+      assert.strictEqual(r1.value, arr)
+    } else {
+      assert.fail('is not a Some')
+    }
+    const r2 = updateAt(2, a3, arr)
+    if (r2.isSome()) {
+      assert.strictEqual(r2.value, arr)
+    } else {
+      assert.fail('is not a Some')
+    }
+  })
+
+  it('filter', () => {
+    const make2 = (x: number) => ({ x })
+    const a1 = make2(1)
+    const a2 = make2(1)
+    const a3 = make2(2)
+    const arr = fromNonEmptyArray([a1, a2, a3])
+    assert.deepStrictEqual(filter(arr, ({ x }) => x !== 1), some(fromNonEmptyArray([a3])))
+    assert.deepStrictEqual(filter(arr, ({ x }) => x !== 2), some(fromNonEmptyArray([a1, a2])))
+    assert.deepStrictEqual(
+      filter(arr, ({ x }) => {
+        return !(x === 1 || x === 2)
+      }),
+      none
+    )
+    assert.deepStrictEqual(filter(arr, ({ x }) => x !== 10), some(fromNonEmptyArray([a1, a2, a3])))
+
+    // refinements
+    const actual1 = filter(fromNonEmptyArray([some(3), some(2), some(1)]), isSome)
+    assert.deepStrictEqual(actual1, some(fromNonEmptyArray([some(3), some(2), some(1)])))
+    const actual2 = filter(fromNonEmptyArray([some(3), none, some(1)]), isSome)
+    assert.deepStrictEqual(actual2, some(fromNonEmptyArray([some(3), some(1)])))
+  })
+
+  it('filterWithIndex', () => {
+    assert.deepStrictEqual(
+      filterWithIndex(fromNonEmptyArray([1, 2, 3]), i => i % 2 === 0),
+      some(fromNonEmptyArray([1, 3]))
+    )
+    assert.deepStrictEqual(filterWithIndex(fromNonEmptyArray([1, 2, 3]), (i, a) => i % 2 === 1 && a > 2), none)
+  })
+
+  it('reduceWithIndex', () => {
+    assert.deepStrictEqual(
+      nonEmptyArray.reduceWithIndex(fromNonEmptyArray(['a', 'b']), '', (i, b, a) => b + i + a),
+      '0a1b'
+    )
+  })
+
+  it('foldMapWithIndex', () => {
+    assert.deepStrictEqual(
+      nonEmptyArray.foldMapWithIndex(monoidString)(fromNonEmptyArray(['a', 'b']), (i, a) => i + a),
+      '0a1b'
+    )
+  })
+
+  it('foldrWithIndex', () => {
+    assert.deepStrictEqual(
+      nonEmptyArray.foldrWithIndex(fromNonEmptyArray(['a', 'b']), '', (i, a, b) => b + i + a),
+      '1b0a'
+    )
+  })
+
+  it('traverseWithIndex', () => {
+    const ta = fromNonEmptyArray(['a', 'bb'])
+    assert.deepStrictEqual(
+      nonEmptyArray.traverseWithIndex(option)(ta, (i, s) => (s.length >= 1 ? some(s + i) : none)),
+      some(fromNonEmptyArray(['a0', 'bb1']))
+    )
+    assert.deepStrictEqual(
+      nonEmptyArray.traverseWithIndex(option)(ta, (i, s) => (s.length > 1 ? some(s + i) : none)),
+      none
+    )
+
+    // FoldableWithIndex compatibility
+    const M = monoidString
+    const f = (i: number, s: string): string => s + i
+    assert.deepStrictEqual(
+      nonEmptyArray.foldMapWithIndex(M)(ta, f),
+      nonEmptyArray.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const<string, unknown>(f(i, a))).value
+    )
+
+    // FunctorWithIndex compatibility
+    assert.deepStrictEqual(
+      nonEmptyArray.mapWithIndex(ta, f),
+      nonEmptyArray.traverseWithIndex(I.identity)(ta, (i, a) => new I.Identity(f(i, a))).value
+    )
+  })
+})
diff --git a/test/Reader.ts b/test/Reader.ts
index e238ab65..a5a4fe9b 100644
--- a/test/Reader.ts
+++ b/test/Reader.ts
@@ -6,7 +6,7 @@ import { monoidSum } from '../src/Monoid'
 describe('Reader', () => {
   it('map', () => {
     const double = (n: number): number => n * 2
-    const x = new Reader(() => 1)
+    const x = new Reader<{}, number>(() => 1)
     assert.strictEqual(x.map(double).run({}), 2)
     assert.strictEqual(reader.map(x, double).run({}), 2)
   })
@@ -32,7 +32,7 @@ describe('Reader', () => {
   })
 
   it('ask', () => {
-    const x = ask()
+    const x = ask<number>()
     assert.strictEqual(x.run(1), 1)
   })
 
diff --git a/test/ReaderTaskEither.ts b/test/ReaderTaskEither.ts
index e233d592..c7a901ab 100644
--- a/test/ReaderTaskEither.ts
+++ b/test/ReaderTaskEither.ts
@@ -54,7 +54,7 @@ describe('ReaderTaskEither', () => {
     const double = (n: number): number => n * 2
     return readerTaskEither
       .of<{}, number, number>(1)
-      .chain(() => new ReaderTaskEither(() => taskEitherLeft(task.of(2))))
+      .chain(() => new ReaderTaskEither<{}, number, unknown>(() => taskEitherLeft(task.of(2))))
       .mapLeft(double)
       .run({})
       .then(e => {
@@ -108,7 +108,7 @@ describe('ReaderTaskEither', () => {
   it('local', () => {
     const double = (n: number): number => n * 2
     const doubleLocal = local<number>(double)
-    const rte1 = doubleLocal(new ReaderTaskEither(taskEither.of))
+    const rte1 = doubleLocal(new ReaderTaskEither<number, unknown, number>(taskEither.of))
     type E = string
     interface E2 {
       name: string
@@ -179,8 +179,8 @@ describe('ReaderTaskEither', () => {
   })
 
   it('fromIOEither', () => {
-    const x1 = fromIOEither(new IOEither(new IO(() => eitherRight(1))))
-    const x2 = fromIOEither(new IOEither(new IO(() => eitherLeft('foo'))))
+    const x1 = fromIOEither(new IOEither<unknown, number>(new IO(() => eitherRight(1))))
+    const x2 = fromIOEither(new IOEither<string, unknown>(new IO(() => eitherLeft('foo'))))
     return Promise.all([x1.run({}), x2.run({})]).then(([e1, e2]) => {
       assert.deepStrictEqual(e1, eitherRight(1))
       assert.deepStrictEqual(e2, eitherLeft('foo'))
diff --git a/test/Record.ts b/test/Record.ts
index e11fc069..c7e388f9 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -188,7 +188,7 @@ describe('Record', () => {
   it('wither', () => {
     const witherIdentity = R.wither(I.identity)
     const f = (n: number) => new I.Identity(p(n) ? some(n + 1) : none)
-    assert.deepStrictEqual(witherIdentity({}, f), new I.Identity({}))
+    assert.deepStrictEqual(witherIdentity({}, f), new I.Identity<Record<string, number>>({}))
     assert.deepStrictEqual(witherIdentity({ a: 1, b: 3 }, f), new I.Identity({ b: 4 }))
   })
 
diff --git a/test/State.ts b/test/State.ts
index fa405a1b..b2831430 100644
--- a/test/State.ts
+++ b/test/State.ts
@@ -3,11 +3,11 @@ import { State, get, gets, modify, put, state } from '../src/State'
 
 describe('State', () => {
   it('eval', () => {
-    assert.deepStrictEqual(state.of(1).eval(0), 1)
+    assert.deepStrictEqual(state.of<number, string>('a').eval(0), 'a')
   })
 
   it('exec', () => {
-    assert.deepStrictEqual(state.of(1).exec(0), 0)
+    assert.deepStrictEqual(state.of<number, string>('a').exec(0), 0)
   })
 
   it('put', () => {
diff --git a/test/StrMap.ts b/test/StrMap.ts
index 5508f01a..dc8f4639 100644
--- a/test/StrMap.ts
+++ b/test/StrMap.ts
@@ -150,12 +150,12 @@ describe('StrMap', () => {
   })
 
   it('size', () => {
-    assert.strictEqual(size(new StrMap({})), 0)
+    assert.strictEqual(size(new StrMap<number>({})), 0)
     assert.strictEqual(size(new StrMap({ a: 1 })), 1)
   })
 
   it('isEmpty', () => {
-    assert.strictEqual(isEmpty(new StrMap({})), true)
+    assert.strictEqual(isEmpty(new StrMap<number>({})), true)
     assert.strictEqual(isEmpty(new StrMap({ a: 1 })), false)
   })
 
@@ -216,7 +216,7 @@ describe('StrMap', () => {
 
   it('filterMap', () => {
     const f = (n: number) => (p(n) ? some(n + 1) : none)
-    assert.deepStrictEqual(strmap.filterMap(new StrMap<number>({}), f), new StrMap({}))
+    assert.deepStrictEqual(strmap.filterMap(new StrMap<number>({}), f), new StrMap<number>({}))
     assert.deepStrictEqual(strmap.filterMap(new StrMap({ a: 1, b: 3 }), f), new StrMap({ b: 4 }))
   })
 
@@ -232,7 +232,10 @@ describe('StrMap', () => {
   })
 
   it('partition', () => {
-    assert.deepStrictEqual(strmap.partition(new StrMap<number>({}), p), { left: new StrMap({}), right: new StrMap({}) })
+    assert.deepStrictEqual(strmap.partition(new StrMap<number>({}), p), {
+      left: new StrMap<number>({}),
+      right: new StrMap<number>({})
+    })
     assert.deepStrictEqual(strmap.partition(new StrMap<number>({ a: 1, b: 3 }), p), {
       left: new StrMap({ a: 1 }),
       right: new StrMap({ b: 3 })
@@ -254,8 +257,8 @@ describe('StrMap', () => {
   it('partitionMap', () => {
     const f = (n: number) => (p(n) ? right(n + 1) : left(n - 1))
     assert.deepStrictEqual(strmap.partitionMap(new StrMap<number>({}), f), {
-      left: new StrMap({}),
-      right: new StrMap({})
+      left: new StrMap<number>({}),
+      right: new StrMap<number>({})
     })
     assert.deepStrictEqual(strmap.partitionMap(new StrMap<number>({ a: 1, b: 3 }), f), {
       left: new StrMap({ a: 0 }),
@@ -278,7 +281,7 @@ describe('StrMap', () => {
   it('wither', () => {
     const witherIdentity = strmap.wither(I.identity)
     const f = (n: number) => new I.Identity(p(n) ? some(n + 1) : none)
-    assert.deepStrictEqual(witherIdentity(new StrMap<number>({}), f), new I.Identity(new StrMap({})))
+    assert.deepStrictEqual(witherIdentity(new StrMap<number>({}), f), new I.Identity(new StrMap<number>({})))
     assert.deepStrictEqual(witherIdentity(new StrMap({ a: 1, b: 3 }), f), new I.Identity(new StrMap({ b: 4 })))
   })
 
@@ -287,7 +290,7 @@ describe('StrMap', () => {
     const f = (n: number) => new I.Identity(p(n) ? right(n + 1) : left(n - 1))
     assert.deepStrictEqual(
       wiltIdentity(new StrMap<number>({}), f),
-      new I.Identity({ left: new StrMap({}), right: new StrMap({}) })
+      new I.Identity({ left: new StrMap<number>({}), right: new StrMap<number>({}) })
     )
     assert.deepStrictEqual(
       wiltIdentity(new StrMap({ a: 1, b: 3 }), f),
diff --git a/test/TaskEither.ts b/test/TaskEither.ts
index c6fa81f1..f002627e 100644
--- a/test/TaskEither.ts
+++ b/test/TaskEither.ts
@@ -300,8 +300,8 @@ describe('TaskEither', () => {
   })
 
   it('fromIOEither', () => {
-    const x1 = fromIOEither(new IOEither(new IO(() => eitherRight(1))))
-    const x2 = fromIOEither(new IOEither(new IO(() => eitherLeft('foo'))))
+    const x1 = fromIOEither(new IOEither<string, number>(new IO(() => eitherRight(1))))
+    const x2 = fromIOEither(new IOEither<string, number>(new IO(() => eitherLeft('foo'))))
     return Promise.all([x1.run(), x2.run()]).then(([e1, e2]) => {
       assert.deepStrictEqual(e1, eitherRight(1))
       assert.deepStrictEqual(e2, eitherLeft('foo'))
diff --git a/test/Validation.ts b/test/Validation.ts
index f4a600e9..1ae19c65 100644
--- a/test/Validation.ts
+++ b/test/Validation.ts
@@ -93,13 +93,13 @@ describe('Validation', () => {
 
   it('getOrElse', () => {
     assert.strictEqual(success(12).getOrElse(17), 12)
-    assert.strictEqual(failure(12).getOrElse(17), 17)
-    assert.strictEqual(failure(12).getOrElseL((l: number) => l + 1), 13)
+    assert.strictEqual(failure<string, number>('a').getOrElse(17), 17)
+    assert.strictEqual(failure<string, number>('a').getOrElseL((l: string) => l.length + 1), 2)
   })
 
   it('getOrElseL', () => {
     assert.strictEqual(success(12).getOrElseL(() => 17), 12)
-    assert.strictEqual(failure(12).getOrElseL(() => 17), 17)
+    assert.strictEqual(failure<string, number>('a').getOrElseL(() => 17), 17)
   })
 
   it('mapFailure', () => {