Repository: gcanti/fp-ts
Pull request #670 (2018-12-03 10:36:11)

version 1.12


Patch:
diff --git a/docs/Array.md b/docs/Array.md
index 977ec7bc..342f8cd6 100644
--- a/docs/Array.md
+++ b/docs/Array.md
@@ -13,13 +13,15 @@ title: Module Array
 Monad1<URI> &
   Foldable2v1<URI> &
   Unfoldable1<URI> &
-  Traversable2v1<URI> &
+  TraversableWithIndex1<URI, number> &
   Alternative1<URI> &
   Plus1<URI> &
   Extend1<URI> &
   Compactable1<URI> &
-  Filterable1<URI> &
-  Witherable1<URI>
+  FilterableWithIndex1<URI, number> &
+  Witherable1<URI> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number>
 ```
 
 Added in v1.0.0 (instance)
@@ -198,6 +200,26 @@ assert.deepEqual(deleteAt(0, [1, 2, 3]), some([2, 3]))
 assert.deepEqual(deleteAt(1, []), none)
 ```
 
+## difference
+
+```ts
+<A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>)
+```
+
+Added in v1.12.0 (function)
+
+Creates an array of array values not included in the other given array using a [Setoid](./Setoid.md) for equality
+comparisons. The order and references of result values are determined by the first array.
+
+_Example_
+
+```ts
+import { difference } from 'fp-ts/lib/Array'
+import { setoidNumber } from 'fp-ts/lib/Setoid'
+
+assert.deepEqual(difference(setoidNumber)([1, 2], [2, 3]), [1])
+```
+
 ## drop
 
 ```ts
@@ -262,8 +284,6 @@ Added in v1.0.0 (function)
 
 Filter an array, keeping the elements which satisfy a predicate function, creating a new array
 
-**Note**. `predicate` can be a refinement
-
 ## findFirst
 
 ```ts
@@ -537,6 +557,26 @@ import { some } from 'fp-ts/lib/Option'
 assert.deepEqual(insertAt(2, 5, [1, 2, 3, 4]), some([1, 2, 5, 3, 4]))
 ```
 
+## intersection
+
+```ts
+<A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>)
+```
+
+Added in v1.12.0 (function)
+
+Creates an array of unique values that are included in all given arrays using a [Setoid](./Setoid.md) for equality
+comparisons. The order and references of result values are determined by the first array.
+
+_Example_
+
+```ts
+import { intersection } from 'fp-ts/lib/Array'
+import { setoidNumber } from 'fp-ts/lib/Setoid'
+
+assert.deepEqual(intersection(setoidNumber)([1, 2], [2, 3]), [2])
+```
+
 ## isEmpty
 
 ```ts
@@ -690,6 +730,14 @@ assert.deepEqual(modifyAt([1, 2, 3], 1, double), some([1, 4, 3]))
 assert.deepEqual(modifyAt([], 1, double), none)
 ```
 
+## partition
+
+```ts
+partition<A>(fa: Array<A>, p: Predicate<A>): Separated<Array<A>, Array<A>>
+```
+
+Added in v1.12.0 (function)
+
 ## partitionMap
 
 ```ts
@@ -1074,7 +1122,26 @@ traverse<F>(F: Applicative<F>): <A, B>(ta: Array<A>, f: (a: A) => HKT<F, B>) =>
 
 Added in v1.0.0 (function)
 
-Use `array.traverse`
+Use [array](#array)`.traverse` instead
+
+## union
+
+```ts
+<A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>)
+```
+
+Added in v1.12.0 (function)
+
+Creates an array of unique values, in order, from all given arrays using a [Setoid](./Setoid.md) for equality comparisons
+
+_Example_
+
+```ts
+import { union } from 'fp-ts/lib/Array'
+import { setoidNumber } from 'fp-ts/lib/Setoid'
+
+assert.deepEqual(union(setoidNumber)([1, 2], [2, 3]), [1, 2, 3])
+```
 
 ## uniq
 
diff --git a/docs/Compactable.md b/docs/Compactable.md
index c13a5764..00d68bd9 100644
--- a/docs/Compactable.md
+++ b/docs/Compactable.md
@@ -43,3 +43,14 @@ Added in v1.7.0 (type class)
 [Monad](./Monad.md), [Plus](./Plus.md), and [Traversable](./Traversable.md) in that we can use these classes to provide the ability to
 operate on a data type by eliminating intermediate `None`s. This is useful for representing the filtering out of
 values, or failure.
+
+## getCompactableComposition
+
+```ts
+getCompactableComposition<F, G>(
+  F: Functor<F>,
+  G: Compactable<G> & Functor<G>
+): CompactableComposition<F, G>
+```
+
+Added in v1.12.0 (function)
diff --git a/docs/Filterable.md b/docs/Filterable.md
index 939f62f2..75e94457 100644
--- a/docs/Filterable.md
+++ b/docs/Filterable.md
@@ -33,3 +33,11 @@ interface Filterable<F> extends Functor<F>, Compactable<F> {
 Added in v1.7.0 (type class)
 
 `Filterable` represents data structures which can be _partitioned_/_filtered_.
+
+## getFilterableComposition
+
+```ts
+getFilterableComposition<F, G>(F: Functor<F>, G: Filterable<G>): FilterableComposition<F, G>
+```
+
+Added in v1.12.0 (function)
diff --git a/docs/FilterableWithIndex.md b/docs/FilterableWithIndex.md
new file mode 100644
index 00000000..2365203f
--- /dev/null
+++ b/docs/FilterableWithIndex.md
@@ -0,0 +1,24 @@
+---
+id: FilterableWithIndex
+title: Module FilterableWithIndex
+---
+
+[← Back](.)
+
+[Source](https://github.com/gcanti/fp-ts/blob/master/src/FilterableWithIndex.ts)
+
+# FilterableWithIndex
+
+```ts
+interface FilterableWithIndex<F, I> extends FunctorWithIndex<F, I>, Filterable<F> {
+  readonly partitionMapWithIndex: <RL, RR, A>(
+    fa: HKT<F, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<HKT<F, RL>, HKT<F, RR>>
+  readonly partitionWithIndex: <A>(fa: HKT<F, A>, p: (i: I, a: A) => boolean) => Separated<HKT<F, A>, HKT<F, A>>
+  readonly filterMapWithIndex: <A, B>(fa: HKT<F, A>, f: (i: I, a: A) => Option<B>) => HKT<F, B>
+  readonly filterWithIndex: <A>(fa: HKT<F, A>, p: (i: I, a: A) => boolean) => HKT<F, A>
+}
+```
+
+Added in v1.12.0 (type class)
diff --git a/docs/FoldableWithIndex.md b/docs/FoldableWithIndex.md
new file mode 100644
index 00000000..5a9bc9ed
--- /dev/null
+++ b/docs/FoldableWithIndex.md
@@ -0,0 +1,40 @@
+---
+id: FoldableWithIndex
+title: Module FoldableWithIndex
+---
+
+[← Back](.)
+
+[Source](https://github.com/gcanti/fp-ts/blob/master/src/FoldableWithIndex.ts)
+
+# FoldableWithIndex
+
+```ts
+interface FoldableWithIndex<F, I> extends Foldable2v<F> {
+  readonly reduceWithIndex: <A, B>(fa: HKT<F, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fa: HKT<F, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fa: HKT<F, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+```
+
+Added in v1.12.0 (type class)
+
+A [Foldable](./Foldable.md) with an additional index.
+A `FoldableWithIndex` instance must be compatible with its [Foldable](./Foldable.md) instance
+
+```ts
+reduce(fa, b, f) = reduceWithIndex(fa, b, (_, b, a) => f(b, a))
+foldMap(M)(fa, f) = foldMapWithIndex(M)(fa, (_, a) => f(a))
+foldr(fa, b, f) = foldrWithIndex(fa, b, (_, a, b) => f(a, b))
+```
+
+## getFoldableWithIndexComposition
+
+```ts
+getFoldableWithIndexComposition<F, FI, G, GI>(
+  F: FoldableWithIndex<F, FI>,
+  G: FoldableWithIndex<G, GI>
+): FoldableWithIndexComposition<F, FI, G, GI>
+```
+
+Added in v1.12.0 (function)
diff --git a/docs/FunctorWithIndex.md b/docs/FunctorWithIndex.md
new file mode 100644
index 00000000..d3d8490b
--- /dev/null
+++ b/docs/FunctorWithIndex.md
@@ -0,0 +1,39 @@
+---
+id: FunctorWithIndex
+title: Module FunctorWithIndex
+---
+
+[← Back](.)
+
+[Source](https://github.com/gcanti/fp-ts/blob/master/src/FunctorWithIndex.ts)
+
+# FunctorWithIndex
+
+```ts
+interface FunctorWithIndex<F, I> extends Functor<F> {
+  readonly mapWithIndex: <A, B>(fa: HKT<F, A>, f: (i: I, a: A) => B) => HKT<F, B>
+}
+```
+
+Added in v1.12.0 (type class)
+
+A `FunctorWithIndex` is a type constructor which supports a mapping operation `map`.
+
+`mapWithIndex` can be used to turn functions `i -> a -> b` into functions `f a -> f b` whose argument and return types use the type
+constructor `f` to represent some computational context.
+
+Instances must satisfy the following laws:
+
+1. Identity: `F.mapWithIndex(fa, (_i, a) => a) = fa`
+2. Composition: `F.mapWithIndex(fa, (_i, a) => bc(ab(a))) = F.mapWithIndex(F.mapWithIndex(fa, ab), bc)`
+
+## getFunctorWithIndexComposition
+
+```ts
+getFunctorWithIndexComposition<F, FI, G, GI>(
+  F: FunctorWithIndex<F, FI>,
+  G: FunctorWithIndex<G, GI>
+): FunctorWithIndexComposition<F, FI, G, GI>
+```
+
+Added in v1.12.0 (function)
diff --git a/docs/NonEmptyArray.md b/docs/NonEmptyArray.md
index 5422334d..4c56ed1b 100644
--- a/docs/NonEmptyArray.md
+++ b/docs/NonEmptyArray.md
@@ -10,7 +10,12 @@ title: Module NonEmptyArray
 ## nonEmptyArray
 
 ```ts
-Monad1<URI> & Comonad1<URI> & Foldable2v1<URI> & Traversable2v1<URI>
+Monad1<URI> &
+  Comonad1<URI> &
+  Foldable2v1<URI> &
+  TraversableWithIndex1<URI, number> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number>
 ```
 
 Added in v1.0.0 (instance)
@@ -33,8 +38,6 @@ Data structure which represents non-empty arrays
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Apply](./Apply.md)
-
 _Example_
 
 ```ts
@@ -73,8 +76,6 @@ assert.deepEqual(new NonEmptyArray(double, [double]).ap_(x).toArray(), [2, 4, 2,
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Chain](./Chain.md)
-
 _Example_
 
 ```ts
@@ -93,8 +94,6 @@ assert.deepEqual(x.chain(f).toArray(), [1, 4, 2, 4])
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Semigroup](./Semigroup.md)
-
 _Example_
 
 ```ts
@@ -131,8 +130,6 @@ assert.deepEqual(new NonEmptyArray<number>(1, []).concatArray([2]), new NonEmpty
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Extend](./Extend.md)
-
 _Example_
 
 ```ts
@@ -151,8 +148,6 @@ assert.deepEqual(new NonEmptyArray(1, [2, 3, 4]).extend(sum), new NonEmptyArray(
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Comonad](./Comonad.md)
-
 _Example_
 
 ```ts
@@ -171,6 +166,14 @@ Added in v1.11.0 (method)
 
 Filter an NonEmptyArray, keeping the elements which satisfy a predicate function, creating a new NonEmptyArray or returning `None` in case the resulting NonEmptyArray would have no remaining elements.
 
+## filterWithIndex
+
+```ts
+(predicate: (i: number, a: A) => boolean): Option<NonEmptyArray<A>>
+```
+
+Added in v1.12.0 (method)
+
 ## findFirst
 
 ```ts
@@ -254,6 +257,22 @@ assert.deepEqual(xs.findLastIndex(x => x.a === 1), some(1))
 assert.deepEqual(xs.findLastIndex(x => x.a === 4), none)
 ```
 
+## foldr
+
+```ts
+<B>(b: B, f: (a: A, b: B) => B): B
+```
+
+Added in v1.12.0 (method)
+
+## foldrWithIndex
+
+```ts
+<B>(b: B, f: (i: number, a: A, b: B) => B): B
+```
+
+Added in v1.12.0 (method)
+
 ## index
 
 ```ts
@@ -338,8 +357,6 @@ Added in v1.10.0 (method)
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Functor](./Functor.md)
-
 _Example_
 
 ```ts
@@ -349,6 +366,14 @@ const double = (n: number): number => n * 2
 assert.deepEqual(new NonEmptyArray(1, [2]).map(double), new NonEmptyArray(2, [4]))
 ```
 
+## mapWithIndex
+
+```ts
+<B>(f: (i: number, a: A) => B): NonEmptyArray<B>
+```
+
+Added in v1.0.0 (method)
+
 ## max
 
 ```ts
@@ -395,8 +420,6 @@ assert.strictEqual(new NonEmptyArray(1, [2, 3]).min(ordNumber), 1)
 
 Added in v1.0.0 (method)
 
-Instance-bound implementation of [Foldable](./Foldable.md)
-
 _Example_
 
 ```ts
@@ -406,6 +429,14 @@ const x = new NonEmptyArray('a', ['b'])
 assert.strictEqual(x.reduce('', (b, a) => b + a), 'ab')
 ```
 
+## reduceWithIndex
+
+```ts
+<B>(b: B, f: (i: number, b: B, a: A) => B): B
+```
+
+Added in v1.12.0 (method)
+
 ## reverse
 
 ```ts
diff --git a/docs/Record.md b/docs/Record.md
index e824c048..0308c86c 100644
--- a/docs/Record.md
+++ b/docs/Record.md
@@ -39,14 +39,41 @@ Added in v1.10.0 (function)
 
 Added in v1.10.0 (function)
 
+## filterMapWithIndex
+
+```ts
+<A, B>(
+  fa: Record<string, A>,
+  f: (key: string, a: A) => Option<B>
+): Record<string, B>
+```
+
+Added in v1.12.0 (function)
+
+## filterWithIndex
+
+```ts
+<A>(fa: Record<string, A>, p: (key: string, a: A) => boolean): Record<string, A>
+```
+
+Added in v1.12.0 (function)
+
 ## foldMap
 
 ```ts
-<M>(M: Monoid<M>) => <A>(fa: Record<string, A>, f: (a: A) => M): M
+<M>(M: Monoid<M>): (<A>(fa: Record<string, A>, f: (a: A) => M) => M)
 ```
 
 Added in v1.10.0 (function)
 
+## foldMapWithKey
+
+```ts
+<M>(M: Monoid<M>) => <A>(fa: Record<string, A>, f: (k: string, a: A) => M): M
+```
+
+Added in v1.12.0 (function)
+
 ## foldr
 
 ```ts
@@ -55,6 +82,14 @@ Added in v1.10.0 (function)
 
 Added in v1.10.0 (function)
 
+## foldrWithKey
+
+```ts
+<A, B>(fa: Record<string, A>, b: B, f: (k: string, a: A, b: B) => B): B
+```
+
+Added in v1.12.0 (function)
+
 ## fromFoldable
 
 ```ts
@@ -152,6 +187,28 @@ Added in v1.10.0 (function)
 
 Added in v1.10.0 (function)
 
+## partitionMapWithIndex
+
+```ts
+<RL, RR, A>(
+  fa: Record<string, A>,
+  f: (key: string, a: A) => Either<RL, RR>
+): Separated<Record<string, RL>, Record<string, RR>>
+```
+
+Added in v1.12.0 (function)
+
+## partitionWithIndex
+
+```ts
+<A>(
+  fa: Record<string, A>,
+  p: (key: string, a: A) => boolean
+): Separated<Record<string, A>, Record<string, A>>
+```
+
+Added in v1.12.0 (function)
+
 ## pop
 
 ```ts
@@ -170,6 +227,14 @@ Delete a key and value from a map, returning the value as well as the subsequent
 
 Added in v1.10.0 (function)
 
+## reduceWithKey
+
+```ts
+<A, B>(fa: Record<string, A>, b: B, f: (k: string, b: B, a: A) => B): B
+```
+
+Added in v1.12.0 (function)
+
 ## remove
 
 ```ts
diff --git a/docs/Set.md b/docs/Set.md
index 847f54e6..0be168ce 100644
--- a/docs/Set.md
+++ b/docs/Set.md
@@ -15,7 +15,15 @@ title: Module Set
 
 Added in v1.2.0 (function)
 
-## difference
+## compact
+
+```ts
+<A>(S: Setoid<A>): ((fa: Set<Option<A>>) => Set<A>)
+```
+
+Added in v1.12.0 (function)
+
+## ~~difference~~ (deprecated)
 
 ```ts
 <A>(S: Setoid<A>): ((x: Set<A>, y: Set<A>) => Set<A>)
@@ -23,7 +31,26 @@ Added in v1.2.0 (function)
 
 Added in v1.0.0 (function)
 
-Form the set difference (`y` - `x`)
+Use [difference2v](#difference2v) instead
+
+## difference2v
+
+```ts
+<A>(S: Setoid<A>): ((x: Set<A>, y: Set<A>) => Set<A>)
+```
+
+Added in v1.12.0 (function)
+
+Form the set difference (`x` - `y`)
+
+_Example_
+
+```ts
+import { difference2v } from 'fp-ts/lib/Set'
+import { setoidNumber } from 'fp-ts/lib/Setoid'
+
+assert.deepEqual(difference2v(setoidNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+```
 
 ## every
 
@@ -41,6 +68,14 @@ filter<A>(x: Set<A>, predicate: Predicate<A>): Set<A>
 
 Added in v1.0.0 (function)
 
+## filterMap
+
+```ts
+<B>(S: Setoid<B>): (<A>(fa: Set<A>, f: (a: A) => Option<B>) => Set<B>)
+```
+
+Added in v1.12.0 (function)
+
 ## fromArray
 
 ```ts
@@ -152,6 +187,14 @@ Added in v1.0.0 (function)
 
 Delete a value from a set
 
+## separate
+
+```ts
+<L, R>(SL: Setoid<L>, SR: Setoid<R>) => (fa: Set<Either<L, R>>): Separated<Set<L>, Set<R>>
+```
+
+Added in v1.12.0 (function)
+
 ## singleton
 
 ```ts
diff --git a/docs/StrMap.md b/docs/StrMap.md
index 9a1ca377..4e4a1fae 100644
--- a/docs/StrMap.md
+++ b/docs/StrMap.md
@@ -10,12 +10,13 @@ title: Module StrMap
 ## strmap
 
 ```ts
-Functor1<URI> &
+FunctorWithIndex1<URI, string> &
   Foldable2v1<URI> &
-  Traversable2v1<URI> &
+  TraversableWithIndex1<URI, string> &
   Compactable1<URI> &
-  Filterable1<URI> &
-  Witherable1<URI>
+  FilterableWithIndex1<URI, string> &
+  Witherable1<URI> &
+  FoldableWithIndex1<URI, string>
 ```
 
 Added in v1.0.0 (instance)
@@ -36,6 +37,46 @@ Added in v1.0.0 (data)
 
 Added in v1.4.0 (method)
 
+## filterMap
+
+```ts
+<B>(f: (a: A) => Option<B>): StrMap<B>
+```
+
+Added in v1.12.0 (method)
+
+## filterMapWithIndex
+
+```ts
+<B>(f: (i: string, a: A) => Option<B>): StrMap<B>
+```
+
+Added in v1.12.0 (method)
+
+## filterWithIndex
+
+```ts
+(p: (i: string, a: A) => boolean): StrMap<A>
+```
+
+Added in v1.12.0 (method)
+
+## foldr
+
+```ts
+<B>(b: B, f: (a: A, b: B) => B): B
+```
+
+Added in v1.12.0 (method)
+
+## foldrWithKey
+
+```ts
+<B>(b: B, f: (k: string, a: A, b: B) => B): B
+```
+
+Added in v1.12.0 (method)
+
 ## map
 
 ```ts
@@ -52,6 +93,38 @@ Added in v1.0.0 (method)
 
 Added in v1.0.0 (method)
 
+## partition
+
+```ts
+(p: Predicate<A>): Separated<StrMap<A>, StrMap<A>>
+```
+
+Added in v1.12.0 (method)
+
+## partitionMap
+
+```ts
+<RL, RR>(f: (a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>>
+```
+
+Added in v1.12.0 (method)
+
+## partitionMapWithIndex
+
+```ts
+<RL, RR>(f: (i: string, a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>>
+```
+
+Added in v1.12.0 (method)
+
+## partitionWithIndex
+
+```ts
+(p: (i: string, a: A) => boolean): Separated<StrMap<A>, StrMap<A>>
+```
+
+Added in v1.12.0 (method)
+
 ## reduce
 
 ```ts
@@ -60,6 +133,22 @@ Added in v1.0.0 (method)
 
 Added in v1.0.0 (method)
 
+## reduceWithKey
+
+```ts
+<B>(b: B, f: (k: string, b: B, a: A) => B): B
+```
+
+Added in v1.12.0 (method)
+
+## separate
+
+```ts
+<RL, RR>(this: StrMap<Either<RL, RR>>): Separated<StrMap<RL>, StrMap<RR>>
+```
+
+Added in v1.12.0 (method)
+
 ## empty
 
 ```ts
diff --git a/docs/TaskEither.md b/docs/TaskEither.md
index 913bf2b1..9008da49 100644
--- a/docs/TaskEither.md
+++ b/docs/TaskEither.md
@@ -70,7 +70,7 @@ Flipped version of [ap](#ap)
 
 Added in v1.6.0 (method)
 
-Combine two effectful actions, keeping only the result of the first
+Combine two (parallel) effectful actions, keeping only the result of the first
 
 ## applySecond
 
@@ -80,7 +80,7 @@ Combine two effectful actions, keeping only the result of the first
 
 Added in v1.5.0 (method)
 
-Combine two effectful actions, keeping only the result of the second
+Combine two (parallel) effectful actions, keeping only the result of the second
 
 ## attempt
 
@@ -108,6 +108,26 @@ Added in v1.2.0 (method)
 
 Added in v1.0.0 (method)
 
+## chainFirst
+
+```ts
+<B>(fb: TaskEither<L, B>): TaskEither<L, A>
+```
+
+Added in v1.12.0 (method)
+
+Combine two (sequential) effectful actions, keeping only the result of the first
+
+## chainSecond
+
+```ts
+<B>(fb: TaskEither<L, B>): TaskEither<L, B>
+```
+
+Added in v1.12.0 (method)
+
+Combine two (sequential) effectful actions, keeping only the result of the second
+
 ## filterOrElse
 
 ```ts
diff --git a/docs/TraversableWithIndex.md b/docs/TraversableWithIndex.md
new file mode 100644
index 00000000..4897f9a9
--- /dev/null
+++ b/docs/TraversableWithIndex.md
@@ -0,0 +1,37 @@
+---
+id: TraversableWithIndex
+title: Module TraversableWithIndex
+---
+
+[← Back](.)
+
+[Source](https://github.com/gcanti/fp-ts/blob/master/src/TraversableWithIndex.ts)
+
+# TraversableWithIndex
+
+```ts
+interface TraversableWithIndex<T, I> extends FunctorWithIndex<T, I>, FoldableWithIndex<T, I>, Traversable2v<T> {
+  readonly traverseWithIndex: TraverseWithIndex<T, I>
+}
+```
+
+Added in v1.12.0 (type class)
+
+A [Traversable](./Traversable.md) with an additional index.
+A `TraversableWithIndex` instance must be compatible with its [Traversable](./Traversable.md) instance
+
+```ts
+traverse(F)(ta, f) = traverseWithIndex(F)(ta, (_, a) => f(a))
+```
+
+with its [FoldableWithIndex](./FoldableWithIndex.md) instance
+
+```ts
+foldMapWithIndex(M)(ta, f) = traverseWithIndex(getApplicative(M))(ta, (i, a) => new Const(f(i, a))).value
+```
+
+and with its [FunctorWithIndex](./FunctorWithIndex.md) instance
+
+```purescript
+mapWithIndex(ta, f) = traverseWithIndex(identity)(ta, (i, a) => new Identity(f(i, a))).value
+```
diff --git a/docs/index.md b/docs/index.md
index 891866cb..23ed8058 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -29,10 +29,13 @@
 - [Extend](./Extend.md)
 - [Field](./Field.md)
 - [Filterable](./Filterable.md)
+- [FilterableWithIndex](./FilterableWithIndex.md)
 - [Foldable](./Foldable.md)
 - [Foldable2v](./Foldable2v.md)
+- [FoldableWithIndex](./FoldableWithIndex.md)
 - [Free](./Free.md)
 - [Functor](./Functor.md)
+- [FunctorWithIndex](./FunctorWithIndex.md)
 - [HKT](./HKT.md)
 - [HeytingAlgebra](./HeytingAlgebra.md)
 - [IO](./IO.md)
@@ -80,6 +83,7 @@
 - [Trace](./Trace.md)
 - [Traversable](./Traversable.md)
 - [Traversable2v](./Traversable2v.md)
+- [TraversableWithIndex](./TraversableWithIndex.md)
 - [Tree](./Tree.md)
 - [Tuple](./Tuple.md)
 - [Unfoldable](./Unfoldable.md)
diff --git a/package.json b/package.json
index aeced87e..2a6835cb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "fp-ts",
-  "version": "1.11.3",
+  "version": "1.12.0",
   "description": "Functional programming in TypeScript",
   "files": [
     "lib"
diff --git a/src/Applicative.ts b/src/Applicative.ts
index 35f12548..70f21e6e 100644
--- a/src/Applicative.ts
+++ b/src/Applicative.ts
@@ -69,54 +69,63 @@ export interface ApplicativeComposition11<F extends URIS, G extends URIS> extend
 }
 
 export interface ApplicativeComposition12<F extends URIS, G extends URIS2> extends FunctorComposition12<F, G> {
-  readonly of: <L, A>(a: A) => Type<F, Type2<G, L, A>>
-  readonly ap: <L, A, B>(
-    fgab: Type<F, Type2<G, L, (a: A) => B>>,
-    fga: Type<F, Type2<G, L, A>>
-  ) => Type<F, Type2<G, L, B>>
+  readonly of: <LG, A>(a: A) => Type<F, Type2<G, LG, A>>
+  readonly ap: <LG, A, B>(
+    fgab: Type<F, Type2<G, LG, (a: A) => B>>,
+    fga: Type<F, Type2<G, LG, A>>
+  ) => Type<F, Type2<G, LG, B>>
 }
 
-export interface ApplicativeComposition12C<F extends URIS, G extends URIS2, L> extends FunctorComposition12C<F, G, L> {
-  readonly of: <A>(a: A) => Type<F, Type2<G, L, A>>
-  readonly ap: <A, B>(fgab: Type<F, Type2<G, L, (a: A) => B>>, fga: Type<F, Type2<G, L, A>>) => Type<F, Type2<G, L, B>>
+export interface ApplicativeComposition12C<F extends URIS, G extends URIS2, LG>
+  extends FunctorComposition12C<F, G, LG> {
+  readonly of: <A>(a: A) => Type<F, Type2<G, LG, A>>
+  readonly ap: <A, B>(
+    fgab: Type<F, Type2<G, LG, (a: A) => B>>,
+    fga: Type<F, Type2<G, LG, A>>
+  ) => Type<F, Type2<G, LG, B>>
 }
 
 export interface ApplicativeComposition21<F extends URIS2, G extends URIS> extends FunctorComposition21<F, G> {
-  readonly of: <L, A>(a: A) => Type2<F, L, Type<G, A>>
-  readonly ap: <L, A, B>(
-    fgab: Type2<F, L, Type<G, (a: A) => B>>,
-    fga: Type2<F, L, Type<G, A>>
-  ) => Type2<F, L, Type<G, B>>
+  readonly of: <LF, A>(a: A) => Type2<F, LF, Type<G, A>>
+  readonly ap: <LF, A, B>(
+    fgab: Type2<F, LF, Type<G, (a: A) => B>>,
+    fga: Type2<F, LF, Type<G, A>>
+  ) => Type2<F, LF, Type<G, B>>
 }
 
-export interface ApplicativeComposition2C1<F extends URIS2, G extends URIS, L> extends FunctorComposition2C1<F, G, L> {
-  readonly of: <A>(a: A) => Type2<F, L, Type<G, A>>
-  readonly ap: <A, B>(fgab: Type2<F, L, Type<G, (a: A) => B>>, fga: Type2<F, L, Type<G, A>>) => Type2<F, L, Type<G, B>>
+export interface ApplicativeComposition2C1<F extends URIS2, G extends URIS, LF>
+  extends FunctorComposition2C1<F, G, LF> {
+  readonly of: <A>(a: A) => Type2<F, LF, Type<G, A>>
+  readonly ap: <A, B>(
+    fgab: Type2<F, LF, Type<G, (a: A) => B>>,
+    fga: Type2<F, LF, Type<G, A>>
+  ) => Type2<F, LF, Type<G, B>>
 }
 
 export interface ApplicativeComposition22<F extends URIS2, G extends URIS2> extends FunctorComposition22<F, G> {
-  readonly of: <L, M, A>(a: A) => Type2<F, L, Type2<G, M, A>>
+  readonly of: <LF, LG, A>(a: A) => Type2<F, LF, Type2<G, LG, A>>
   readonly ap: <L, M, A, B>(
     fgab: Type2<F, L, Type2<G, M, (a: A) => B>>,
     fga: Type2<F, L, Type2<G, M, A>>
   ) => Type2<F, L, Type2<G, M, B>>
 }
 
-export interface ApplicativeComposition22C<F extends URIS2, G extends URIS2, M> extends FunctorComposition22C<F, G, M> {
-  readonly of: <L, A>(a: A) => Type2<F, L, Type2<G, M, A>>
-  readonly ap: <L, A, B>(
-    fgab: Type2<F, L, Type2<G, M, (a: A) => B>>,
-    fga: Type2<F, L, Type2<G, M, A>>
-  ) => Type2<F, L, Type2<G, M, B>>
+export interface ApplicativeComposition22C<F extends URIS2, G extends URIS2, LG>
+  extends FunctorComposition22C<F, G, LG> {
+  readonly of: <LF, A>(a: A) => Type2<F, LF, Type2<G, LG, A>>
+  readonly ap: <LF, A, B>(
+    fgab: Type2<F, LF, Type2<G, LG, (a: A) => B>>,
+    fga: Type2<F, LF, Type2<G, LG, A>>
+  ) => Type2<F, LF, Type2<G, LG, B>>
 }
 
-export interface ApplicativeComposition3C1<F extends URIS3, G extends URIS, U, L>
-  extends FunctorComposition3C1<F, G, U, L> {
-  readonly of: <A>(a: A) => Type3<F, U, L, Type<G, A>>
+export interface ApplicativeComposition3C1<F extends URIS3, G extends URIS, UF, LF>
+  extends FunctorComposition3C1<F, G, UF, LF> {
+  readonly of: <A>(a: A) => Type3<F, UF, LF, Type<G, A>>
   readonly ap: <A, B>(
-    fgab: Type3<F, U, L, Type<G, (a: A) => B>>,
-    fga: Type3<F, U, L, Type<G, A>>
-  ) => Type3<F, U, L, Type<G, B>>
+    fgab: Type3<F, UF, LF, Type<G, (a: A) => B>>,
+    fga: Type3<F, UF, LF, Type<G, A>>
+  ) => Type3<F, UF, LF, Type<G, B>>
 }
 
 /**
@@ -162,14 +171,22 @@ export function when<F>(F: Applicative<F>): (condition: boolean, fu: HKT<F, void
  * @function
  * @since 1.0.0
  */
+export function getApplicativeComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Applicative3C<F, UF, LF>,
+  G: Applicative1<G>
+): ApplicativeComposition3C1<F, G, UF, LF>
+export function getApplicativeComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Applicative2<F>,
+  G: Applicative2C<G, LG>
+): ApplicativeComposition22C<F, G, LG>
 export function getApplicativeComposition<F extends URIS2, G extends URIS2>(
   F: Applicative2<F>,
   G: Applicative2<G>
 ): ApplicativeComposition22<F, G>
-export function getApplicativeComposition<F extends URIS2, G extends URIS2, L>(
+export function getApplicativeComposition<F extends URIS2, G extends URIS2, LG>(
   F: Applicative2<F>,
-  G: Applicative2C<G, L>
-): ApplicativeComposition22C<F, G, L>
+  G: Applicative2C<G, LG>
+): ApplicativeComposition22C<F, G, LG>
 export function getApplicativeComposition<F extends URIS2, G extends URIS>(
   F: Applicative2<F>,
   G: Applicative1<G>
@@ -178,10 +195,10 @@ export function getApplicativeComposition<F extends URIS, G extends URIS2>(
   F: Applicative1<F>,
   G: Applicative2<G>
 ): ApplicativeComposition12<F, G>
-export function getApplicativeComposition<F extends URIS, G extends URIS2, L>(
+export function getApplicativeComposition<F extends URIS, G extends URIS2, LG>(
   F: Applicative1<F>,
-  G: Applicative2C<G, L>
-): ApplicativeComposition12C<F, G, L>
+  G: Applicative2C<G, LG>
+): ApplicativeComposition12C<F, G, LG>
 export function getApplicativeComposition<F extends URIS, G extends URIS>(
   F: Applicative1<F>,
   G: Applicative1<G>
diff --git a/src/Array.ts b/src/Array.ts
index b0ff989b..39b2bda7 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -3,9 +3,11 @@ import { Applicative, Applicative1, Applicative2, Applicative2C, Applicative3, A
 import { Compactable1, Separated } from './Compactable'
 import { Either } from './Either'
 import { Extend1 } from './Extend'
-import { Filterable1 } from './Filterable'
+import { FilterableWithIndex1 } from './FilterableWithIndex'
 import { Foldable2v1 } from './Foldable2v'
+import { FoldableWithIndex1 } from './FoldableWithIndex'
 import { concat, Endomorphism, identity, Predicate, Refinement, tuple } from './function'
+import { FunctorWithIndex1 } from './FunctorWithIndex'
 import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 import { Monad1 } from './Monad'
 import { Monoid } from './Monoid'
@@ -14,7 +16,7 @@ import { getSemigroup, Ord, ordNumber } from './Ord'
 import { Ordering } from './Ordering'
 import { Plus1 } from './Plus'
 import { getArraySetoid, Setoid } from './Setoid'
-import { Traversable2v1 } from './Traversable2v'
+import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable1 } from './Unfoldable'
 import { Witherable1 } from './Witherable'
 
@@ -111,12 +113,11 @@ export const getOrd = <A>(O: Ord<A>): Ord<Array<A>> => ({
 })
 
 const map = <A, B>(fa: Array<A>, f: (a: A) => B): Array<B> => {
-  const l = fa.length
-  const r = new Array(l)
-  for (let i = 0; i < l; i++) {
-    r[i] = f(fa[i])
-  }
-  return r
+  return fa.map(f)
+}
+
+const mapWithIndex = <A, B>(fa: Array<A>, f: (index: number, a: A) => B): Array<B> => {
+  return fa.map((a, i) => f(i, a))
 }
 
 const of = <A>(a: A): Array<A> => {
@@ -151,24 +152,37 @@ const chain = <A, B>(fa: Array<A>, f: (a: A) => Array<B>): Array<B> => {
 }
 
 const reduce = <A, B>(fa: Array<A>, b: B, f: (b: B, a: A) => B): B => {
+  return reduceWithIndex(fa, b, (_, b, a) => f(b, a))
+}
+
+const foldMap = <M>(M: Monoid<M>): (<A>(fa: Array<A>, f: (a: A) => M) => M) => {
+  const foldMapWithIndexM = foldMapWithIndex(M)
+  return (fa, f) => foldMapWithIndexM(fa, (_, a) => f(a))
+}
+
+const reduceRight = <A, B>(fa: Array<A>, b: B, f: (a: A, b: B) => B): B => {
+  return foldrWithIndex(fa, b, (_, a, b) => f(a, b))
+}
+
+const reduceWithIndex = <A, B>(fa: Array<A>, b: B, f: (i: number, b: B, a: A) => B): B => {
   const l = fa.length
   let r = b
   for (let i = 0; i < l; i++) {
-    r = f(r, fa[i])
+    r = f(i, r, fa[i])
   }
   return r
 }
 
-const foldMap = <M>(M: Monoid<M>) => <A>(fa: Array<A>, f: (a: A) => M): M => {
-  return fa.reduce((b, a) => M.concat(b, f(a)), M.empty)
+const foldMapWithIndex = <M>(M: Monoid<M>) => <A>(fa: Array<A>, f: (i: number, a: A) => M): M => {
+  return fa.reduce((b, a, i) => M.concat(b, f(i, a)), M.empty)
 }
 
-const reduceRight = <A, B>(fa: Array<A>, b: B, f: (a: A, b: B) => B): B => {
-  return fa.reduceRight((b, a) => f(a, b), b)
+const foldrWithIndex = <A, B>(fa: Array<A>, b: B, f: (i: number, a: A, b: B) => B): B => {
+  return fa.reduceRight((b, a, i) => f(i, a, b), b)
 }
 
 /**
- * Use `array.traverse`
+ * Use {@link array}`.traverse` instead
  * @function
  * @since 1.0.0
  * @deprecated
@@ -190,8 +204,8 @@ export function traverse<F extends URIS>(
 ): <A, B>(ta: Array<A>, f: (a: A) => Type<F, B>) => Type<F, Array<B>>
 export function traverse<F>(F: Applicative<F>): <A, B>(ta: Array<A>, f: (a: A) => HKT<F, B>) => HKT<F, Array<B>>
 export function traverse<F>(F: Applicative<F>): <A, B>(ta: Array<A>, f: (a: A) => HKT<F, B>) => HKT<F, Array<B>> {
-  return <A, B>(ta: Array<A>, f: (a: A) => HKT<F, B>) =>
-    reduce(ta, F.of<Array<B>>(zero()), (fbs, a) => F.ap(F.map(fbs, bs => (b: B) => snoc(bs, b)), f(a)))
+  const traverseWithIndexF = traverseWithIndex(F)
+  return (ta, f) => traverseWithIndexF(ta, (_, a) => f(a))
 }
 
 const sequence = <F>(F: Applicative<F>) => <A>(ta: Array<HKT<F, A>>): HKT<F, Array<A>> => {
@@ -1194,14 +1208,7 @@ export const sortBy1 = <A>(head: Ord<A>, tail: Array<Ord<A>>): Endomorphism<Arra
  * @since 1.0.0
  */
 export const mapOption = <A, B>(as: Array<A>, f: (a: A) => Option<B>): Array<B> => {
-  const result: Array<B> = []
-  for (const a of as) {
-    const optionB = f(a)
-    if (optionB.isSome()) {
-      result.push(optionB.value)
-    }
-  }
-  return result
+  return filterMapWithIndex(as, (_, a) => f(a))
 }
 
 /**
@@ -1234,27 +1241,11 @@ export const catOptions = <A>(as: Array<Option<A>>): Array<A> => {
  * @since 1.0.0
  */
 export const partitionMap = <A, L, R>(fa: Array<A>, f: (a: A) => Either<L, R>): Separated<Array<L>, Array<R>> => {
-  const left: Array<L> = []
-  const right: Array<R> = []
-  for (const a of fa) {
-    const e = f(a)
-    if (e.isLeft()) {
-      left.push(e.value)
-    } else {
-      right.push(e.value)
-    }
-  }
-  return {
-    left,
-    right
-  }
+  return partitionMapWithIndex(fa, (_, a) => f(a))
 }
 
 /**
  * Filter an array, keeping the elements which satisfy a predicate function, creating a new array
- *
- * **Note**. `predicate` can be a refinement
- *
  * @function
  * @since 1.0.0
  */
@@ -1264,20 +1255,14 @@ export function filter<A>(as: Array<A>, predicate: Predicate<A>): Array<A> {
   return as.filter(predicate)
 }
 
-const partition = <A>(fa: Array<A>, p: Predicate<A>): Separated<Array<A>, Array<A>> => {
-  const left: Array<A> = []
-  const right: Array<A> = []
-  for (const a of fa) {
-    if (p(a)) {
-      right.push(a)
-    } else {
-      left.push(a)
-    }
-  }
-  return {
-    left,
-    right
-  }
+/**
+ * @function
+ * @since 1.12.0
+ */
+export function partition<A, B extends A>(fa: Array<A>, p: Refinement<A, B>): Separated<Array<A>, Array<B>>
+export function partition<A>(fa: Array<A>, p: Predicate<A>): Separated<Array<A>, Array<A>>
+export function partition<A>(fa: Array<A>, p: Predicate<A>): Separated<Array<A>, Array<A>> {
+  return partitionWithIndex(fa, (_, a) => p(a))
 }
 
 const compact = catOptions
@@ -1434,6 +1419,120 @@ export function comprehension<R>(
   return go(empty, input)
 }
 
+/**
+ * Creates an array of unique values, in order, from all given arrays using a {@link Setoid} for equality comparisons
+ *
+ * @example
+ * import { union } from 'fp-ts/lib/Array'
+ * import { setoidNumber } from 'fp-ts/lib/Setoid'
+ *
+ * assert.deepEqual(union(setoidNumber)([1, 2], [2, 3]), [1, 2, 3])
+ *
+ * @function
+ * @since 1.12.0
+ */
+export const union = <A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>) => {
+  const memberS = member(S)
+  return (xs, ys) => concat(xs, ys.filter(a => !memberS(xs, a)))
+}
+
+/**
+ * Creates an array of unique values that are included in all given arrays using a {@link Setoid} for equality
+ * comparisons. The order and references of result values are determined by the first array.
+ *
+ * @example
+ * import { intersection } from 'fp-ts/lib/Array'
+ * import { setoidNumber } from 'fp-ts/lib/Setoid'
+ *
+ * assert.deepEqual(intersection(setoidNumber)([1, 2], [2, 3]), [2])
+ *
+ * @function
+ * @since 1.12.0
+ */
+export const intersection = <A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>) => {
+  const memberS = member(S)
+  return (xs, ys) => xs.filter(a => memberS(ys, a))
+}
+
+/**
+ * Creates an array of array values not included in the other given array using a {@link Setoid} for equality
+ * comparisons. The order and references of result values are determined by the first array.
+ *
+ * @example
+ * import { difference } from 'fp-ts/lib/Array'
+ * import { setoidNumber } from 'fp-ts/lib/Setoid'
+ *
+ * assert.deepEqual(difference(setoidNumber)([1, 2], [2, 3]), [1])
+ *
+ * @function
+ * @since 1.12.0
+ */
+export const difference = <A>(S: Setoid<A>): ((xs: Array<A>, ys: Array<A>) => Array<A>) => {
+  const memberS = member(S)
+  return (xs, ys) => xs.filter(a => !memberS(ys, a))
+}
+
+const traverseWithIndex = <F>(F: Applicative<F>) => <A, B>(
+  ta: Array<A>,
+  f: (i: number, a: A) => HKT<F, B>
+): HKT<F, Array<B>> => {
+  return reduceWithIndex(ta, F.of<Array<B>>(zero()), (i, fbs, a) =>
+    F.ap(F.map(fbs, bs => (b: B) => snoc(bs, b)), f(i, a))
+  )
+}
+
+const partitionMapWithIndex = <RL, RR, A>(
+  fa: Array<A>,
+  f: (i: number, a: A) => Either<RL, RR>
+): Separated<Array<RL>, Array<RR>> => {
+  const left: Array<RL> = []
+  const right: Array<RR> = []
+  for (let i = 0; i < fa.length; i++) {
+    const e = f(i, fa[i])
+    if (e.isLeft()) {
+      left.push(e.value)
+    } else {
+      right.push(e.value)
+    }
+  }
+  return {
+    left,
+    right
+  }
+}
+
+const partitionWithIndex = <A>(fa: Array<A>, p: (i: number, a: A) => boolean): Separated<Array<A>, Array<A>> => {
+  const left: Array<A> = []
+  const right: Array<A> = []
+  for (let i = 0; i < fa.length; i++) {
+    const a = fa[i]
+    if (p(i, a)) {
+      right.push(a)
+    } else {
+      left.push(a)
+    }
+  }
+  return {
+    left,
+    right
+  }
+}
+
+const filterMapWithIndex = <A, B>(fa: Array<A>, f: (i: number, a: A) => Option<B>): Array<B> => {
+  const result: Array<B> = []
+  for (let i = 0; i < fa.length; i++) {
+    const optionB = f(i, fa[i])
+    if (optionB.isSome()) {
+      result.push(optionB.value)
+    }
+  }
+  return result
+}
+
+const filterWithIndex = <A>(fa: Array<A>, p: (i: number, a: A) => boolean): Array<A> => {
+  return fa.filter((a, i) => p(i, a))
+}
+
 /**
  * @instance
  * @since 1.0.0
@@ -1441,15 +1540,18 @@ export function comprehension<R>(
 export const array: Monad1<URI> &
   Foldable2v1<URI> &
   Unfoldable1<URI> &
-  Traversable2v1<URI> &
+  TraversableWithIndex1<URI, number> &
   Alternative1<URI> &
   Plus1<URI> &
   Extend1<URI> &
   Compactable1<URI> &
-  Filterable1<URI> &
-  Witherable1<URI> = {
+  FilterableWithIndex1<URI, number> &
+  Witherable1<URI> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number> = {
   URI,
   map,
+  mapWithIndex,
   compact,
   separate,
   filter,
@@ -1469,5 +1571,13 @@ export const array: Monad1<URI> &
   alt,
   extend,
   wither,
-  wilt
+  wilt,
+  reduceWithIndex,
+  foldMapWithIndex,
+  foldrWithIndex,
+  traverseWithIndex,
+  partitionMapWithIndex,
+  partitionWithIndex,
+  filterMapWithIndex,
+  filterWithIndex
 }
diff --git a/src/Compactable.ts b/src/Compactable.ts
index 0c51c948..3f774032 100644
--- a/src/Compactable.ts
+++ b/src/Compactable.ts
@@ -1,6 +1,23 @@
-import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
-import { Option } from './Option'
 import { Either } from './Either'
+import {
+  Functor,
+  Functor1,
+  Functor2,
+  Functor2C,
+  Functor3C,
+  FunctorComposition,
+  FunctorComposition11,
+  FunctorComposition12,
+  FunctorComposition12C,
+  FunctorComposition21,
+  FunctorComposition22,
+  FunctorComposition22C,
+  FunctorComposition2C1,
+  FunctorComposition3C1,
+  getFunctorComposition
+} from './Functor'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { fromEither, none, Option, some } from './Option'
 
 /**
  * A `Separated` type which holds `left` and `right` parts.
@@ -36,30 +53,18 @@ export interface Compactable<F> {
   readonly separate: <A, B>(fa: HKT<F, Either<A, B>>) => Separated<HKT<F, A>, HKT<F, B>>
 }
 
-/**
- * @see Compactable
- * @since 1.7.0
- */
 export interface Compactable1<F extends URIS> {
   readonly URI: F
   readonly compact: <A>(fa: Type<F, Option<A>>) => Type<F, A>
   readonly separate: <A, B>(fa: Type<F, Either<A, B>>) => Separated<Type<F, A>, Type<F, B>>
 }
 
-/**
- * @see Compactable
- * @since 1.7.0
- */
 export interface Compactable2<F extends URIS2> {
   readonly URI: F
   readonly compact: <L, A>(fa: Type2<F, L, Option<A>>) => Type2<F, L, A>
   readonly separate: <L, A, B>(fa: Type2<F, L, Either<A, B>>) => Separated<Type2<F, L, A>, Type2<F, L, B>>
 }
 
-/**
- * @see Compactable
- * @since 1.7.0
- */
 export interface Compactable2C<F extends URIS2, L> {
   readonly URI: F
   readonly _L: L
@@ -67,20 +72,12 @@ export interface Compactable2C<F extends URIS2, L> {
   readonly separate: <A, B>(fa: Type2<F, L, Either<A, B>>) => Separated<Type2<F, L, A>, Type2<F, L, B>>
 }
 
-/**
- * @see Compactable
- * @since 1.7.0
- */
 export interface Compactable3<F extends URIS3> {
   readonly URI: F
   readonly compact: <U, L, A>(fa: Type3<F, U, L, Option<A>>) => Type3<F, U, L, A>
   readonly separate: <U, L, A, B>(fa: Type3<F, U, L, Either<A, B>>) => Separated<Type3<F, U, L, A>, Type3<F, U, L, B>>
 }
 
-/**
- * @see Compactable
- * @since 1.7.0
- */
 export interface Compactable3C<F extends URIS3, U, L> {
   readonly URI: F
   readonly _L: L
@@ -88,3 +85,123 @@ export interface Compactable3C<F extends URIS3, U, L> {
   readonly compact: <A>(fa: Type3<F, U, L, Option<A>>) => Type3<F, U, L, A>
   readonly separate: <A, B>(fa: Type3<F, U, L, Either<A, B>>) => Separated<Type3<F, U, L, A>, Type3<F, U, L, B>>
 }
+
+export interface CompactableComposition<F, G> extends FunctorComposition<F, G> {
+  readonly compact: <A>(fga: HKT<F, HKT<G, Option<A>>>) => HKT<F, HKT<G, A>>
+  readonly separate: <A, B>(fge: HKT<F, HKT<G, Either<A, B>>>) => Separated<HKT<F, HKT<G, A>>, HKT<F, HKT<G, B>>>
+}
+
+export interface CompactableComposition11<F extends URIS, G extends URIS> extends FunctorComposition11<F, G> {
+  readonly compact: <A>(fga: Type<F, Type<G, Option<A>>>) => Type<F, Type<G, A>>
+  readonly separate: <A, B>(fge: Type<F, Type<G, Either<A, B>>>) => Separated<Type<F, Type<G, A>>, Type<F, Type<G, B>>>
+}
+
+export interface CompactableComposition12<F extends URIS, G extends URIS2> extends FunctorComposition12<F, G> {
+  readonly compact: <LG, A>(fga: Type<F, Type2<G, LG, Option<A>>>) => Type<F, Type2<G, LG, A>>
+  readonly separate: <LG, A, B>(
+    fge: Type<F, Type2<G, LG, Either<A, B>>>
+  ) => Separated<Type<F, Type2<G, LG, A>>, Type<F, Type2<G, LG, B>>>
+}
+
+export interface CompactableComposition12C<F extends URIS, G extends URIS2, LG>
+  extends FunctorComposition12C<F, G, LG> {
+  readonly compact: <A>(fga: Type<F, Type2<G, LG, Option<A>>>) => Type<F, Type2<G, LG, A>>
+  readonly separate: <A, B>(
+    fge: Type<F, Type2<G, LG, Either<A, B>>>
+  ) => Separated<Type<F, Type2<G, LG, A>>, Type<F, Type2<G, LG, B>>>
+}
+
+export interface CompactableComposition21<F extends URIS2, G extends URIS> extends FunctorComposition21<F, G> {
+  readonly compact: <LF, A>(fga: Type2<F, LF, Type<G, Option<A>>>) => Type2<F, LF, Type<G, A>>
+  readonly separate: <LF, A, B>(
+    fge: Type2<F, LF, Type<G, Either<A, B>>>
+  ) => Separated<Type2<F, LF, Type<G, A>>, Type2<F, LF, Type<G, B>>>
+}
+
+export interface CompactableComposition2C1<F extends URIS2, G extends URIS, LF>
+  extends FunctorComposition2C1<F, G, LF> {
+  readonly compact: <A>(fga: Type2<F, LF, Type<G, Option<A>>>) => Type2<F, LF, Type<G, A>>
+  readonly separate: <A, B>(
+    fge: Type2<F, LF, Type<G, Either<A, B>>>
+  ) => Separated<Type2<F, LF, Type<G, A>>, Type2<F, LF, Type<G, B>>>
+}
+
+export interface CompactableComposition22<F extends URIS2, G extends URIS2> extends FunctorComposition22<F, G> {
+  readonly compact: <LF, LG, A>(fga: Type2<F, LF, Type2<G, LG, Option<A>>>) => Type2<F, LF, Type2<G, LG, A>>
+  readonly separate: <LF, LG, A, B>(
+    fge: Type2<F, LF, Type2<G, LG, Either<A, B>>>
+  ) => Separated<Type2<F, LF, Type2<G, LG, A>>, Type2<F, LF, Type2<G, LG, B>>>
+}
+
+export interface CompactableComposition22C<F extends URIS2, G extends URIS2, LG>
+  extends FunctorComposition22C<F, G, LG> {
+  readonly compact: <LF, A>(fga: Type2<F, LF, Type2<G, LG, Option<A>>>) => Type2<F, LF, Type2<G, LG, A>>
+  readonly separate: <LF, A, B>(
+    fge: Type2<F, LF, Type2<G, LG, Either<A, B>>>
+  ) => Separated<Type2<F, LF, Type2<G, LG, A>>, Type2<F, LF, Type2<G, LG, B>>>
+}
+
+export interface CompactableComposition3C1<F extends URIS3, G extends URIS, UF, LF>
+  extends FunctorComposition3C1<F, G, UF, LF> {
+  readonly compact: <A>(fga: Type3<F, UF, LF, Type<G, Option<A>>>) => Type3<F, UF, LF, Type<G, A>>
+  readonly separate: <A, B>(
+    fge: Type3<F, UF, LF, Type<G, Either<A, B>>>
+  ) => Separated<Type3<F, UF, LF, Type<G, A>>, Type3<F, UF, LF, Type<G, B>>>
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export function getCompactableComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Functor3C<F, UF, LF>,
+  G: Compactable1<G> & Functor1<G>
+): CompactableComposition3C1<F, G, UF, LF>
+export function getCompactableComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Functor2<F>,
+  G: Compactable2C<G, LG> & Functor2C<G, LG>
+): CompactableComposition22C<F, G, LG>
+export function getCompactableComposition<F extends URIS2, G extends URIS2>(
+  F: Functor2<F>,
+  G: Compactable2<G> & Functor2<G>
+): CompactableComposition22<F, G>
+export function getCompactableComposition<F extends URIS2, G extends URIS, LF>(
+  F: Functor2C<F, LF>,
+  G: Compactable1<G> & Functor1<G>
+): CompactableComposition2C1<F, G, LF>
+export function getCompactableComposition<F extends URIS2, G extends URIS>(
+  F: Functor2<F>,
+  G: Compactable1<G> & Functor1<G>
+): CompactableComposition21<F, G>
+export function getCompactableComposition<F extends URIS, G extends URIS2, LG>(
+  F: Functor1<F>,
+  G: Compactable2C<G, LG> & Functor2C<G, LG>
+): CompactableComposition12<F, G>
+export function getCompactableComposition<F extends URIS, G extends URIS2>(
+  F: Functor1<F>,
+  G: Compactable2<G> & Functor2<G>
+): CompactableComposition12<F, G>
+export function getCompactableComposition<F extends URIS, G extends URIS>(
+  F: Functor1<F>,
+  G: Compactable1<G> & Functor1<G>
+): CompactableComposition11<F, G>
+export function getCompactableComposition<F, G>(
+  F: Functor<F>,
+  G: Compactable<G> & Functor<G>
+): CompactableComposition<F, G>
+export function getCompactableComposition<F, G>(
+  F: Functor<F>,
+  G: Compactable<G> & Functor<G>
+): CompactableComposition<F, G> {
+  const FC = getFunctorComposition(F, G)
+  const CC: CompactableComposition<F, G> = {
+    ...FC,
+    compact: fga => F.map(fga, G.compact),
+    separate: fge => {
+      const left = CC.compact(FC.map(fge, e => e.fold(some, () => none)))
+      const right = CC.compact(FC.map(fge, fromEither))
+      return { left, right }
+    }
+  }
+  return CC
+}
diff --git a/src/Filterable.ts b/src/Filterable.ts
index ba5b6eb3..1d5e2c99 100644
--- a/src/Filterable.ts
+++ b/src/Filterable.ts
@@ -1,4 +1,3 @@
-import { Functor, Functor1, Functor2, Functor2C, Functor3, Functor3C } from './Functor'
 import {
   Compactable,
   Compactable1,
@@ -6,12 +5,35 @@ import {
   Compactable2C,
   Compactable3,
   Compactable3C,
+  CompactableComposition,
+  CompactableComposition11,
+  CompactableComposition12,
+  CompactableComposition12C,
+  CompactableComposition21,
+  CompactableComposition22,
+  CompactableComposition3C1,
+  getCompactableComposition,
   Separated
 } from './Compactable'
-import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 import { Either } from './Either'
 import { Predicate } from './function'
-import { Option } from './Option'
+import {
+  Functor,
+  Functor1,
+  Functor2,
+  Functor2C,
+  Functor3,
+  Functor3C,
+  FunctorComposition,
+  FunctorComposition11,
+  FunctorComposition12,
+  FunctorComposition12C,
+  FunctorComposition21,
+  FunctorComposition22,
+  FunctorComposition3C1
+} from './Functor'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { Option, some, none } from './Option'
 
 /**
  * `Filterable` represents data structures which can be _partitioned_/_filtered_.
@@ -108,3 +130,195 @@ export interface Filterable3C<F extends URIS3, U, L> extends Functor3C<F, U, L>,
   readonly filterMap: <A, B>(fa: Type3<F, U, L, A>, f: (a: A) => Option<B>) => Type3<F, U, L, B>
   readonly filter: <A>(fa: Type3<F, U, L, A>, p: Predicate<A>) => Type3<F, U, L, A>
 }
+
+export interface FilterableComposition<F, G> extends FunctorComposition<F, G>, CompactableComposition<F, G> {
+  readonly partitionMap: <RL, RR, A>(
+    fa: HKT<F, HKT<G, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<HKT<F, HKT<G, RL>>, HKT<F, HKT<G, RR>>>
+  readonly partition: <A>(fa: HKT<F, HKT<G, A>>, p: Predicate<A>) => Separated<HKT<F, HKT<G, A>>, HKT<F, HKT<G, A>>>
+  readonly filterMap: <A, B>(fa: HKT<F, HKT<G, A>>, f: (a: A) => Option<B>) => HKT<F, HKT<G, B>>
+  readonly filter: <A>(fa: HKT<F, HKT<G, A>>, p: Predicate<A>) => HKT<F, HKT<G, A>>
+}
+
+export interface FilterableComposition11<F extends URIS, G extends URIS>
+  extends FunctorComposition11<F, G>,
+    CompactableComposition11<F, G> {
+  readonly partitionMap: <RL, RR, A>(
+    fa: Type<F, Type<G, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type<F, Type<G, RL>>, Type<F, Type<G, RR>>>
+  readonly partition: <A>(
+    fa: Type<F, Type<G, A>>,
+    p: Predicate<A>
+  ) => Separated<Type<F, Type<G, A>>, Type<F, Type<G, A>>>
+  readonly filterMap: <A, B>(fa: Type<F, Type<G, A>>, f: (a: A) => Option<B>) => Type<F, Type<G, B>>
+  readonly filter: <A>(fa: Type<F, Type<G, A>>, p: Predicate<A>) => Type<F, Type<G, A>>
+}
+
+export interface FilterableComposition12<F extends URIS, G extends URIS2>
+  extends FunctorComposition12<F, G>,
+    CompactableComposition12<F, G> {
+  readonly partitionMap: <LG, RL, RR, A>(
+    fa: Type<F, Type2<G, LG, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type<F, Type2<G, LG, RL>>, Type<F, Type2<G, LG, RR>>>
+  readonly partition: <LG, A>(
+    fa: Type<F, Type2<G, LG, A>>,
+    p: Predicate<A>
+  ) => Separated<Type<F, Type2<G, LG, A>>, Type<F, Type2<G, LG, A>>>
+  readonly filterMap: <LG, A, B>(fa: Type<F, Type2<G, LG, A>>, f: (a: A) => Option<B>) => Type<F, Type2<G, LG, B>>
+  readonly filter: <LG, A>(fa: Type<F, Type2<G, LG, A>>, p: Predicate<A>) => Type<F, Type2<G, LG, A>>
+}
+
+export interface FilterableComposition12C<F extends URIS, G extends URIS2, LG>
+  extends FunctorComposition12C<F, G, LG>,
+    CompactableComposition12C<F, G, LG> {
+  readonly partitionMap: <RL, RR, A>(
+    fa: Type<F, Type2<G, LG, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type<F, Type2<G, LG, RL>>, Type<F, Type2<G, LG, RR>>>
+  readonly partition: <A>(
+    fa: Type<F, Type2<G, LG, A>>,
+    p: Predicate<A>
+  ) => Separated<Type<F, Type2<G, LG, A>>, Type<F, Type2<G, LG, A>>>
+  readonly filterMap: <A, B>(fa: Type<F, Type2<G, LG, A>>, f: (a: A) => Option<B>) => Type<F, Type2<G, LG, B>>
+  readonly filter: <A>(fa: Type<F, Type2<G, LG, A>>, p: Predicate<A>) => Type<F, Type2<G, LG, A>>
+}
+
+export interface FilterableComposition21<F extends URIS2, G extends URIS>
+  extends FunctorComposition21<F, G>,
+    CompactableComposition21<F, G> {
+  readonly partitionMap: <LF, RL, RR, A>(
+    fa: Type2<F, LF, Type<G, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, LF, Type<G, RL>>, Type2<F, LF, Type<G, RR>>>
+  readonly partition: <LF, A>(
+    fa: Type2<F, LF, Type<G, A>>,
+    p: Predicate<A>
+  ) => Separated<Type2<F, LF, Type<G, A>>, Type2<F, LF, Type<G, A>>>
+  readonly filterMap: <LF, A, B>(fa: Type2<F, LF, Type<G, A>>, f: (a: A) => Option<B>) => Type2<F, LF, Type<G, B>>
+  readonly filter: <LF, A>(fa: Type2<F, LF, Type<G, A>>, p: Predicate<A>) => Type2<F, LF, Type<G, A>>
+}
+
+export interface FilterableComposition2C1<F extends URIS2, G extends URIS, LF>
+  extends FunctorComposition21<F, G>,
+    CompactableComposition21<F, G> {
+  readonly partitionMap: <RL, RR, A>(
+    fa: Type2<F, LF, Type<G, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, LF, Type<G, RL>>, Type2<F, LF, Type<G, RR>>>
+  readonly partition: <A>(
+    fa: Type2<F, LF, Type<G, A>>,
+    p: Predicate<A>
+  ) => Separated<Type2<F, LF, Type<G, A>>, Type2<F, LF, Type<G, A>>>
+  readonly filterMap: <A, B>(fa: Type2<F, LF, Type<G, A>>, f: (a: A) => Option<B>) => Type2<F, LF, Type<G, B>>
+  readonly filter: <A>(fa: Type2<F, LF, Type<G, A>>, p: Predicate<A>) => Type2<F, LF, Type<G, A>>
+}
+
+export interface FilterableComposition22<F extends URIS2, G extends URIS2>
+  extends FunctorComposition22<F, G>,
+    CompactableComposition22<F, G> {
+  readonly partitionMap: <LF, LG, RL, RR, A>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, LF, Type2<G, LG, RL>>, Type2<F, LF, Type2<G, LG, RR>>>
+  readonly partition: <LF, LG, A>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    p: Predicate<A>
+  ) => Separated<Type2<F, LF, Type2<G, LG, A>>, Type2<F, LF, Type2<G, LG, A>>>
+  readonly filterMap: <LF, LG, A, B>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    f: (a: A) => Option<B>
+  ) => Type2<F, LF, Type2<G, LG, B>>
+  readonly filter: <LF, LG, A>(fa: Type2<F, LF, Type2<G, LG, A>>, p: Predicate<A>) => Type2<F, LF, Type2<G, LG, A>>
+}
+
+export interface FilterableComposition22C<F extends URIS2, G extends URIS2, LG>
+  extends FunctorComposition22<F, G>,
+    CompactableComposition22<F, G> {
+  readonly partitionMap: <LF, RL, RR, A>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, LF, Type2<G, LG, RL>>, Type2<F, LF, Type2<G, LG, RR>>>
+  readonly partition: <LF, A>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    p: Predicate<A>
+  ) => Separated<Type2<F, LF, Type2<G, LG, A>>, Type2<F, LF, Type2<G, LG, A>>>
+  readonly filterMap: <LF, A, B>(
+    fa: Type2<F, LF, Type2<G, LG, A>>,
+    f: (a: A) => Option<B>
+  ) => Type2<F, LF, Type2<G, LG, B>>
+  readonly filter: <LF, A>(fa: Type2<F, LF, Type2<G, LG, A>>, p: Predicate<A>) => Type2<F, LF, Type2<G, LG, A>>
+}
+
+export interface FilterableComposition3C1<F extends URIS3, G extends URIS, UF, LF>
+  extends FunctorComposition3C1<F, G, UF, LF>,
+    CompactableComposition3C1<F, G, UF, LF> {
+  readonly partitionMap: <RL, RR, A>(
+    fa: Type3<F, UF, LF, Type<G, A>>,
+    f: (a: A) => Either<RL, RR>
+  ) => Separated<Type3<F, UF, LF, Type<G, RL>>, Type3<F, UF, LF, Type<G, RR>>>
+  readonly partition: <A>(
+    fa: Type3<F, UF, LF, Type<G, A>>,
+    p: Predicate<A>
+  ) => Separated<Type3<F, UF, LF, Type<G, A>>, Type3<F, UF, LF, Type<G, A>>>
+  readonly filterMap: <A, B>(fa: Type3<F, UF, LF, Type<G, A>>, f: (a: A) => Option<B>) => Type3<F, UF, LF, Type<G, B>>
+  readonly filter: <A>(fa: Type3<F, UF, LF, Type<G, A>>, p: Predicate<A>) => Type3<F, UF, LF, Type<G, A>>
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export function getFilterableComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Functor3C<F, UF, LF>,
+  G: Filterable1<G>
+): FilterableComposition3C1<F, G, UF, LF>
+export function getFilterableComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Functor2<F>,
+  G: Filterable2C<G, LG>
+): FilterableComposition22C<F, G, LG>
+export function getFilterableComposition<F extends URIS2, G extends URIS2>(
+  F: Functor2<F>,
+  G: Filterable2<G>
+): FilterableComposition22<F, G>
+export function getFilterableComposition<F extends URIS2, G extends URIS, LF>(
+  F: Functor2C<F, LF>,
+  G: Filterable1<G>
+): FilterableComposition2C1<F, G, LF>
+export function getFilterableComposition<F extends URIS2, G extends URIS>(
+  F: Functor2<F>,
+  G: Filterable1<G>
+): FilterableComposition21<F, G>
+export function getFilterableComposition<F extends URIS, G extends URIS2, LG>(
+  F: Functor1<F>,
+  G: Filterable2C<G, LG>
+): FilterableComposition12C<F, G, LG>
+export function getFilterableComposition<F extends URIS, G extends URIS2>(
+  F: Functor1<F>,
+  G: Filterable2<G>
+): FilterableComposition12<F, G>
+export function getFilterableComposition<F extends URIS, G extends URIS>(
+  F: Functor1<F>,
+  G: Filterable1<G>
+): FilterableComposition11<F, G>
+export function getFilterableComposition<F, G>(F: Functor<F>, G: Filterable<G>): FilterableComposition<F, G>
+export function getFilterableComposition<F, G>(F: Functor<F>, G: Filterable<G>): FilterableComposition<F, G> {
+  const FC: FilterableComposition<F, G> = {
+    ...getCompactableComposition(F, G),
+    partitionMap: (fga, f) => {
+      const left = FC.filterMap(fga, a => f(a).fold(some, () => none))
+      const right = FC.filterMap(fga, a => f(a).fold(() => none, some))
+      return { left, right }
+    },
+    partition: (fga, p) => {
+      const left = FC.filter(fga, a => !p(a))
+      const right = FC.filter(fga, p)
+      return { left, right }
+    },
+    filterMap: (fga, f) => F.map(fga, ga => G.filterMap(ga, f)),
+    filter: (fga, f) => F.map(fga, ga => G.filter(ga, f))
+  }
+  return FC
+}
diff --git a/src/FilterableWithIndex.ts b/src/FilterableWithIndex.ts
new file mode 100644
index 00000000..e52086de
--- /dev/null
+++ b/src/FilterableWithIndex.ts
@@ -0,0 +1,91 @@
+import { Separated } from './Compactable'
+import { Either } from './Either'
+import { Filterable, Filterable1, Filterable2, Filterable2C, Filterable3, Filterable3C } from './Filterable'
+import {
+  FunctorWithIndex,
+  FunctorWithIndex1,
+  FunctorWithIndex2,
+  FunctorWithIndex2C,
+  FunctorWithIndex3,
+  FunctorWithIndex3C
+} from './FunctorWithIndex'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { Option } from './Option'
+
+/**
+ * @typeclass
+ * @since 1.12.0
+ */
+export interface FilterableWithIndex<F, I> extends FunctorWithIndex<F, I>, Filterable<F> {
+  readonly partitionMapWithIndex: <RL, RR, A>(
+    fa: HKT<F, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<HKT<F, RL>, HKT<F, RR>>
+  readonly partitionWithIndex: <A>(fa: HKT<F, A>, p: (i: I, a: A) => boolean) => Separated<HKT<F, A>, HKT<F, A>>
+  readonly filterMapWithIndex: <A, B>(fa: HKT<F, A>, f: (i: I, a: A) => Option<B>) => HKT<F, B>
+  readonly filterWithIndex: <A>(fa: HKT<F, A>, p: (i: I, a: A) => boolean) => HKT<F, A>
+}
+
+export interface FilterableWithIndex1<F extends URIS, I> extends FunctorWithIndex1<F, I>, Filterable1<F> {
+  readonly partitionMapWithIndex: <RL, RR, A>(
+    fa: Type<F, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<Type<F, RL>, Type<F, RR>>
+  readonly partitionWithIndex: <A>(fa: Type<F, A>, p: (i: I, a: A) => boolean) => Separated<Type<F, A>, Type<F, A>>
+  readonly filterMapWithIndex: <A, B>(fa: Type<F, A>, f: (i: I, a: A) => Option<B>) => Type<F, B>
+  readonly filterWithIndex: <A>(fa: Type<F, A>, p: (i: I, a: A) => boolean) => Type<F, A>
+}
+
+export interface FilterableWithIndex2<F extends URIS2, I> extends FunctorWithIndex2<F, I>, Filterable2<F> {
+  readonly partitionMapWithIndex: <RL, RR, L, A>(
+    fa: Type2<F, L, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, L, RL>, Type2<F, L, RR>>
+  readonly partitionWithIndex: <L, A>(
+    fa: Type2<F, L, A>,
+    p: (i: I, a: A) => boolean
+  ) => Separated<Type2<F, L, A>, Type2<F, L, A>>
+  readonly filterMapWithIndex: <L, A, B>(fa: Type2<F, L, A>, f: (i: I, a: A) => Option<B>) => Type2<F, L, B>
+  readonly filterWithIndex: <L, A>(fa: Type2<F, L, A>, p: (i: I, a: A) => boolean) => Type2<F, L, A>
+}
+
+export interface FilterableWithIndex2C<F extends URIS2, I, L> extends FunctorWithIndex2C<F, I, L>, Filterable2C<F, L> {
+  readonly partitionMapWithIndex: <RL, RR, A>(
+    fa: Type2<F, L, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<Type2<F, L, RL>, Type2<F, L, RR>>
+  readonly partitionWithIndex: <A>(
+    fa: Type2<F, L, A>,
+    p: (i: I, a: A) => boolean
+  ) => Separated<Type2<F, L, A>, Type2<F, L, A>>
+  readonly filterMapWithIndex: <A, B>(fa: Type2<F, L, A>, f: (i: I, a: A) => Option<B>) => Type2<F, L, B>
+  readonly filterWithIndex: <A>(fa: Type2<F, L, A>, p: (i: I, a: A) => boolean) => Type2<F, L, A>
+}
+
+export interface FilterableWithIndex3<F extends URIS3, I> extends FunctorWithIndex3<F, I>, Filterable3<F> {
+  readonly partitionMapWithIndex: <RL, RR, U, L, A>(
+    fa: Type3<F, U, L, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<Type3<F, U, L, RL>, Type3<F, U, L, RR>>
+  readonly partitionWithIndex: <U, L, A>(
+    fa: Type3<F, U, L, A>,
+    p: (i: I, a: A) => boolean
+  ) => Separated<Type3<F, U, L, A>, Type3<F, U, L, A>>
+  readonly filterMapWithIndex: <U, L, A, B>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => Option<B>) => Type3<F, U, L, B>
+  readonly filterWithIndex: <U, L, A>(fa: Type3<F, U, L, A>, p: (i: I, a: A) => boolean) => Type3<F, U, L, A>
+}
+
+export interface FilterableWithIndex3C<F extends URIS3, I, U, L>
+  extends FunctorWithIndex3C<F, I, U, L>,
+    Filterable3C<F, U, L> {
+  readonly partitionMapWithIndex: <RL, RR, A>(
+    fa: Type3<F, U, L, A>,
+    f: (i: I, a: A) => Either<RL, RR>
+  ) => Separated<Type3<F, U, L, RL>, Type3<F, U, L, RR>>
+  readonly partitionWithIndex: <A>(
+    fa: Type3<F, U, L, A>,
+    p: (i: I, a: A) => boolean
+  ) => Separated<Type3<F, U, L, A>, Type3<F, U, L, A>>
+  readonly filterMapWithIndex: <A, B>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => Option<B>) => Type3<F, U, L, B>
+  readonly filterWithIndex: <A>(fa: Type3<F, U, L, A>, p: (i: I, a: A) => boolean) => Type3<F, U, L, A>
+}
diff --git a/src/Foldable.ts b/src/Foldable.ts
index 02b9974d..8a850421 100644
--- a/src/Foldable.ts
+++ b/src/Foldable.ts
@@ -58,21 +58,45 @@ export interface FoldableComposition11<F extends URIS, G extends URIS> {
 }
 
 export interface FoldableComposition12<F extends URIS, G extends URIS2> {
-  readonly reduce: <L, A, B>(fga: Type<F, Type2<G, L, A>>, b: B, f: (b: B, a: A) => B) => B
+  readonly reduce: <LG, A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (b: B, a: A) => B) => B
+}
+
+export interface FoldableComposition12C<F extends URIS, G extends URIS2, LG> {
+  readonly reduce: <A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (b: B, a: A) => B) => B
 }
 
 export interface FoldableComposition21<F extends URIS2, G extends URIS> {
-  readonly reduce: <L, A, B>(fga: Type2<F, L, Type<G, A>>, b: B, f: (b: B, a: A) => B) => B
+  readonly reduce: <LF, A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (b: B, a: A) => B) => B
+}
+
+export interface FoldableComposition2C1<F extends URIS2, G extends URIS, LF> {
+  readonly reduce: <A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (b: B, a: A) => B) => B
 }
 
 export interface FoldableComposition22<F extends URIS2, G extends URIS2> {
   readonly reduce: <LF, LG, A, B>(fga: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (b: B, a: A) => B) => B
 }
 
+export interface FoldableComposition22C<F extends URIS2, G extends URIS2, LG> {
+  readonly reduce: <LF, A, B>(fga: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (b: B, a: A) => B) => B
+}
+
+export interface FoldableComposition3C1<F extends URIS3, G extends URIS, UF, LF> {
+  readonly reduce: <A, B>(fga: Type3<F, UF, LF, Type<G, A>>, b: B, f: (b: B, a: A) => B) => B
+}
+
 /**
  * @function
  * @since 1.0.0
  */
+export function getFoldableComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Foldable3C<F, UF, LF>,
+  G: Foldable1<G>
+): FoldableComposition3C1<F, G, UF, LF>
+export function getFoldableComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Foldable2C<F, LG>,
+  G: Foldable2<G>
+): FoldableComposition22C<F, G, LG>
 export function getFoldableComposition<F extends URIS2, G extends URIS2>(
   F: Foldable2<F>,
   G: Foldable2<G>
diff --git a/src/Foldable2v.ts b/src/Foldable2v.ts
index 78bf978e..da69e1ed 100644
--- a/src/Foldable2v.ts
+++ b/src/Foldable2v.ts
@@ -20,7 +20,11 @@ import {
   FoldableComposition12,
   FoldableComposition21,
   FoldableComposition22,
-  foldMap
+  foldMap,
+  FoldableComposition12C,
+  FoldableComposition2C1,
+  FoldableComposition22C,
+  FoldableComposition3C1
 } from './Foldable'
 import { applyFirst } from './Apply'
 
@@ -70,12 +74,24 @@ export interface Foldable2vComposition11<F extends URIS, G extends URIS> extends
 
 export interface Foldable2vComposition12<F extends URIS, G extends URIS2> extends FoldableComposition12<F, G> {
   readonly foldMap: <M>(M: Monoid<M>) => <L, A>(fa: Type<F, Type2<G, L, A>>, f: (a: A) => M) => M
-  readonly foldr: <L, A, B>(fa: Type<F, Type2<G, L, A>>, b: B, f: (a: A, b: B) => B) => B
+  readonly foldr: <LG, A, B>(fa: Type<F, Type2<G, LG, A>>, b: B, f: (a: A, b: B) => B) => B
+}
+
+export interface Foldable2vComposition12C<F extends URIS, G extends URIS2, LG>
+  extends FoldableComposition12C<F, G, LG> {
+  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: Type<F, Type2<G, LG, A>>, f: (a: A) => M) => M
+  readonly foldr: <A, B>(fa: Type<F, Type2<G, LG, A>>, b: B, f: (a: A, b: B) => B) => B
 }
 
 export interface Foldable2vComposition21<F extends URIS2, G extends URIS> extends FoldableComposition21<F, G> {
   readonly foldMap: <M>(M: Monoid<M>) => <L, A>(fa: Type2<F, L, Type<G, A>>, f: (a: A) => M) => M
-  readonly foldr: <L, A, B>(fa: Type2<F, L, Type<G, A>>, b: B, f: (a: A, b: B) => B) => B
+  readonly foldr: <LF, A, B>(fa: Type2<F, LF, Type<G, A>>, b: B, f: (a: A, b: B) => B) => B
+}
+
+export interface Foldable2vComposition2C1<F extends URIS2, G extends URIS, LF>
+  extends FoldableComposition2C1<F, G, LF> {
+  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: Type2<F, LF, Type<G, A>>, f: (a: A) => M) => M
+  readonly foldr: <A, B>(fa: Type2<F, LF, Type<G, A>>, b: B, f: (a: A, b: B) => B) => B
 }
 
 export interface Foldable2vComposition22<F extends URIS2, G extends URIS2> extends FoldableComposition22<F, G> {
@@ -83,6 +99,18 @@ export interface Foldable2vComposition22<F extends URIS2, G extends URIS2> exten
   readonly foldr: <LF, LG, A, B>(fa: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (a: A, b: B) => B) => B
 }
 
+export interface Foldable2vComposition22C<F extends URIS2, G extends URIS2, LG>
+  extends FoldableComposition22C<F, G, LG> {
+  readonly foldMap: <M>(M: Monoid<M>) => <LF, A>(fa: Type2<F, LF, Type2<G, LG, A>>, f: (a: A) => M) => M
+  readonly foldr: <LF, A, B>(fa: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (a: A, b: B) => B) => B
+}
+
+export interface Foldable2vComposition3C1<F extends URIS3, G extends URIS, UF, LF>
+  extends FoldableComposition3C1<F, G, UF, LF> {
+  readonly foldMap: <M>(M: Monoid<M>) => <A>(fa: Type3<F, UF, LF, Type<G, A>>, f: (a: A) => M) => M
+  readonly foldr: <LF, A, B>(fa: Type3<F, UF, LF, Type<G, A>>, b: B, f: (a: A, b: B) => B) => B
+}
+
 /**
  * Returns the composition of two foldables
  *
@@ -99,14 +127,30 @@ export interface Foldable2vComposition22<F extends URIS2, G extends URIS2> exten
  * @function
  * @since 1.10.0
  */
+export function getFoldableComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Foldable2v3C<F, UF, LF>,
+  G: Foldable2v1<G>
+): Foldable2vComposition3C1<F, G, UF, LF>
+export function getFoldableComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Foldable2v2<F>,
+  G: Foldable2v2C<G, LG>
+): Foldable2vComposition22C<F, G, LG>
 export function getFoldableComposition<F extends URIS2, G extends URIS2>(
   F: Foldable2v2<F>,
   G: Foldable2v2<G>
 ): Foldable2vComposition22<F, G>
+export function getFoldableComposition<F extends URIS2, G extends URIS, LF>(
+  F: Foldable2v2C<F, LF>,
+  G: Foldable2v1<G>
+): Foldable2vComposition2C1<F, G, LF>
 export function getFoldableComposition<F extends URIS2, G extends URIS>(
   F: Foldable2v2<F>,
   G: Foldable2v1<G>
 ): Foldable2vComposition21<F, G>
+export function getFoldableComposition<F extends URIS, G extends URIS2, LG>(
+  F: Foldable2v1<F>,
+  G: Foldable2v2C<G, LG>
+): Foldable2vComposition12C<F, G, LG>
 export function getFoldableComposition<F extends URIS, G extends URIS2>(
   F: Foldable2v1<F>,
   G: Foldable2v2<G>
diff --git a/src/FoldableWithIndex.ts b/src/FoldableWithIndex.ts
new file mode 100644
index 00000000..5c4cf81a
--- /dev/null
+++ b/src/FoldableWithIndex.ts
@@ -0,0 +1,207 @@
+import {
+  Foldable2v,
+  Foldable2v1,
+  Foldable2v2,
+  Foldable2v2C,
+  Foldable2v3,
+  Foldable2v3C,
+  Foldable2vComposition,
+  getFoldableComposition,
+  Foldable2vComposition11,
+  Foldable2vComposition12,
+  Foldable2vComposition12C,
+  Foldable2vComposition21,
+  Foldable2vComposition2C1,
+  Foldable2vComposition22,
+  Foldable2vComposition22C,
+  Foldable2vComposition3C1
+} from './Foldable2v'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { Monoid } from './Monoid'
+
+/**
+ * A {@link Foldable} with an additional index.
+ * A `FoldableWithIndex` instance must be compatible with its {@link Foldable} instance
+ *
+ * ```ts
+ * reduce(fa, b, f) = reduceWithIndex(fa, b, (_, b, a) => f(b, a))
+ * foldMap(M)(fa, f) = foldMapWithIndex(M)(fa, (_, a) => f(a))
+ * foldr(fa, b, f) = foldrWithIndex(fa, b, (_, a, b) => f(a, b))
+ * ```
+ *
+ * @typeclass
+ * @since 1.12.0
+ */
+export interface FoldableWithIndex<F, I> extends Foldable2v<F> {
+  readonly reduceWithIndex: <A, B>(fa: HKT<F, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fa: HKT<F, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fa: HKT<F, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndex1<F extends URIS, I> extends Foldable2v1<F> {
+  readonly reduceWithIndex: <A, B>(fa: Type<F, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fa: Type<F, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fa: Type<F, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndex2<F extends URIS2, I> extends Foldable2v2<F> {
+  readonly reduceWithIndex: <L, A, B>(fa: Type2<F, L, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <L, A>(fa: Type2<F, L, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <L, A, B>(fa: Type2<F, L, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndex3<F extends URIS3, I> extends Foldable2v3<F> {
+  readonly reduceWithIndex: <U, L, A, B>(fa: Type3<F, U, L, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <U, L, A>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <U, L, A, B>(fa: Type3<F, U, L, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndex2C<F extends URIS2, I, L> extends Foldable2v2C<F, L> {
+  readonly reduceWithIndex: <A, B>(fa: Type2<F, L, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fa: Type2<F, L, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fa: Type2<F, L, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndex3C<F extends URIS3, I, U, L> extends Foldable2v3C<F, U, L> {
+  readonly reduceWithIndex: <A, B>(fa: Type3<F, U, L, A>, b: B, f: (i: I, b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fa: Type3<F, U, L, A>, b: B, f: (i: I, a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition<F, FI, G, GI> extends Foldable2vComposition<F, G> {
+  readonly reduceWithIndex: <A, B>(fga: HKT<F, HKT<G, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fga: HKT<F, HKT<G, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fga: HKT<F, HKT<G, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition11<F extends URIS, FI, G extends URIS, GI>
+  extends Foldable2vComposition11<F, G> {
+  readonly reduceWithIndex: <A, B>(fga: Type<F, Type<G, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fga: Type<F, Type<G, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fga: Type<F, Type<G, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition12<F extends URIS, FI, G extends URIS2, GI>
+  extends Foldable2vComposition12<F, G> {
+  readonly reduceWithIndex: <LG, A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(
+    M: Monoid<M>
+  ) => <LG, A>(fga: Type<F, Type2<G, LG, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <LG, A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition12C<F extends URIS, FI, G extends URIS2, GI, LG>
+  extends Foldable2vComposition12C<F, G, LG> {
+  readonly reduceWithIndex: <A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fga: Type<F, Type2<G, LG, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fga: Type<F, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition21<F extends URIS2, FI, G extends URIS, GI>
+  extends Foldable2vComposition21<F, G> {
+  readonly reduceWithIndex: <LF, A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(
+    M: Monoid<M>
+  ) => <LF, A>(fga: Type2<F, LF, Type<G, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <LF, A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition2C1<F extends URIS2, FI, G extends URIS, GI, LF>
+  extends Foldable2vComposition2C1<F, G, LF> {
+  readonly reduceWithIndex: <A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(M: Monoid<M>) => <A>(fga: Type2<F, LF, Type<G, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fga: Type2<F, LF, Type<G, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition22<F extends URIS2, FI, G extends URIS2, GI>
+  extends Foldable2vComposition22<F, G> {
+  readonly reduceWithIndex: <LF, LG, A, B>(
+    fga: Type2<F, LF, Type2<G, LG, A>>,
+    b: B,
+    f: (i: [FI, GI], b: B, a: A) => B
+  ) => B
+  readonly foldMapWithIndex: <M>(
+    M: Monoid<M>
+  ) => <LF, LG, A>(fga: Type2<F, LF, Type2<G, LG, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <LF, LG, A, B>(
+    fga: Type2<F, LF, Type2<G, LG, A>>,
+    b: B,
+    f: (i: [FI, GI], a: A, b: B) => B
+  ) => B
+}
+
+export interface FoldableWithIndexComposition22C<F extends URIS2, FI, G extends URIS2, GI, LG>
+  extends Foldable2vComposition22C<F, G, LG> {
+  readonly reduceWithIndex: <LF, A, B>(fga: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(
+    M: Monoid<M>
+  ) => <LF, A>(fga: Type2<F, LF, Type2<G, LG, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <LF, A, B>(fga: Type2<F, LF, Type2<G, LG, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+export interface FoldableWithIndexComposition3C1<F extends URIS3, FI, G extends URIS, GI, UF, LF>
+  extends Foldable2vComposition3C1<F, G, UF, LF> {
+  readonly reduceWithIndex: <A, B>(fga: Type3<F, UF, LF, Type<G, A>>, b: B, f: (i: [FI, GI], b: B, a: A) => B) => B
+  readonly foldMapWithIndex: <M>(
+    M: Monoid<M>
+  ) => <A>(fga: Type3<F, UF, LF, Type<G, A>>, f: (i: [FI, GI], a: A) => M) => M
+  readonly foldrWithIndex: <A, B>(fga: Type3<F, UF, LF, Type<G, A>>, b: B, f: (i: [FI, GI], a: A, b: B) => B) => B
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export function getFoldableWithIndexComposition<F extends URIS3, FI, G extends URIS, GI, UF, LF>(
+  F: FoldableWithIndex3C<F, FI, UF, LF>,
+  G: FoldableWithIndex1<G, GI>
+): FoldableWithIndexComposition3C1<F, FI, G, GI, UF, LF>
+export function getFoldableWithIndexComposition<F extends URIS2, FI, G extends URIS2, GI, LG>(
+  F: FoldableWithIndex2<F, FI>,
+  G: FoldableWithIndex2C<G, GI, LG>
+): FoldableWithIndexComposition22C<F, FI, G, GI, LG>
+export function getFoldableWithIndexComposition<F extends URIS2, FI, G extends URIS2, GI>(
+  F: FoldableWithIndex2<F, FI>,
+  G: FoldableWithIndex2<G, GI>
+): FoldableWithIndexComposition22<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F extends URIS2, FI, G extends URIS, GI, LF>(
+  F: FoldableWithIndex2C<F, FI, LF>,
+  G: FoldableWithIndex1<G, GI>
+): FoldableWithIndexComposition2C1<F, FI, G, GI, LF>
+export function getFoldableWithIndexComposition<F extends URIS2, FI, G extends URIS, GI>(
+  F: FoldableWithIndex2<F, FI>,
+  G: FoldableWithIndex1<G, GI>
+): FoldableWithIndexComposition21<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F extends URIS, FI, G extends URIS2, GI>(
+  F: FoldableWithIndex1<F, FI>,
+  G: FoldableWithIndex2<G, GI>
+): FoldableWithIndexComposition12<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F extends URIS, FI, G extends URIS2, GI>(
+  F: FoldableWithIndex1<F, FI>,
+  G: FoldableWithIndex2<G, GI>
+): FoldableWithIndexComposition12<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F extends URIS, FI, G extends URIS, GI>(
+  F: FoldableWithIndex1<F, FI>,
+  G: FoldableWithIndex1<G, GI>
+): FoldableWithIndexComposition11<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F, FI, G, GI>(
+  F: FoldableWithIndex<F, FI>,
+  G: FoldableWithIndex<G, GI>
+): FoldableWithIndexComposition<F, FI, G, GI>
+export function getFoldableWithIndexComposition<F, FI, G, GI>(
+  F: FoldableWithIndex<F, FI>,
+  G: FoldableWithIndex<G, GI>
+): FoldableWithIndexComposition<F, FI, G, GI> {
+  return {
+    ...getFoldableComposition(F, G),
+    reduceWithIndex: (fga, b, f) =>
+      F.reduceWithIndex(fga, b, (fi, b, ga) => G.reduceWithIndex(ga, b, (gi, b, a) => f([fi, gi], b, a))),
+    foldMapWithIndex: M => {
+      const foldMapWithIndexF = F.foldMapWithIndex(M)
+      const foldMapWithIndexG = G.foldMapWithIndex(M)
+      return (fga, f) => foldMapWithIndexF(fga, (fi, ga) => foldMapWithIndexG(ga, (gi, a) => f([fi, gi], a)))
+    },
+    foldrWithIndex: (fga, b, f) =>
+      F.foldrWithIndex(fga, b, (fi, ga, b) => G.foldrWithIndex(ga, b, (gi, a, b) => f([fi, gi], a, b)))
+  }
+}
diff --git a/src/Functor.ts b/src/Functor.ts
index 2c4f1d48..a4ecb4fc 100644
--- a/src/Functor.ts
+++ b/src/Functor.ts
@@ -62,31 +62,31 @@ export interface FunctorComposition11<F extends URIS, G extends URIS> {
 }
 
 export interface FunctorComposition12<F extends URIS, G extends URIS2> {
-  readonly map: <L, A, B>(fa: Type<F, Type2<G, L, A>>, f: (a: A) => B) => Type<F, Type2<G, L, B>>
+  readonly map: <LG, A, B>(fa: Type<F, Type2<G, LG, A>>, f: (a: A) => B) => Type<F, Type2<G, LG, B>>
 }
 
-export interface FunctorComposition12C<F extends URIS, G extends URIS2, L> {
-  readonly map: <A, B>(fa: Type<F, Type2<G, L, A>>, f: (a: A) => B) => Type<F, Type2<G, L, B>>
+export interface FunctorComposition12C<F extends URIS, G extends URIS2, LG> {
+  readonly map: <A, B>(fa: Type<F, Type2<G, LG, A>>, f: (a: A) => B) => Type<F, Type2<G, LG, B>>
 }
 
 export interface FunctorComposition21<F extends URIS2, G extends URIS> {
-  readonly map: <L, A, B>(fa: Type2<F, L, Type<G, A>>, f: (a: A) => B) => Type2<F, L, Type<G, B>>
+  readonly map: <LF, A, B>(fa: Type2<F, LF, Type<G, A>>, f: (a: A) => B) => Type2<F, LF, Type<G, B>>
 }
 
-export interface FunctorComposition2C1<F extends URIS2, G extends URIS, L> {
-  readonly map: <A, B>(fa: Type2<F, L, Type<G, A>>, f: (a: A) => B) => Type2<F, L, Type<G, B>>
+export interface FunctorComposition2C1<F extends URIS2, G extends URIS, LF> {
+  readonly map: <A, B>(fa: Type2<F, LF, Type<G, A>>, f: (a: A) => B) => Type2<F, LF, Type<G, B>>
 }
 
 export interface FunctorComposition22<F extends URIS2, G extends URIS2> {
-  readonly map: <L, M, A, B>(fa: Type2<F, L, Type2<G, M, A>>, f: (a: A) => B) => Type2<F, L, Type2<G, M, B>>
+  readonly map: <LF, LG, A, B>(fa: Type2<F, LF, Type2<G, LG, A>>, f: (a: A) => B) => Type2<F, LF, Type2<G, LG, B>>
 }
 
-export interface FunctorComposition22C<F extends URIS2, G extends URIS2, M> {
-  readonly map: <L, A, B>(fa: Type2<F, L, Type2<G, M, A>>, f: (a: A) => B) => Type2<F, L, Type2<G, M, B>>
+export interface FunctorComposition22C<F extends URIS2, G extends URIS2, LG> {
+  readonly map: <LF, A, B>(fa: Type2<F, LF, Type2<G, LG, A>>, f: (a: A) => B) => Type2<F, LF, Type2<G, LG, B>>
 }
 
-export interface FunctorComposition3C1<F extends URIS3, G extends URIS, U, L> {
-  readonly map: <A, B>(fa: Type3<F, U, L, Type<G, A>>, f: (a: A) => B) => Type3<F, U, L, Type<G, B>>
+export interface FunctorComposition3C1<F extends URIS3, G extends URIS, UF, LF> {
+  readonly map: <A, B>(fa: Type3<F, UF, LF, Type<G, A>>, f: (a: A) => B) => Type3<F, UF, LF, Type<G, B>>
 }
 
 /**
@@ -177,14 +177,30 @@ export function flap<F>(functor: Functor<F>): <A, B>(a: A, ff: HKT<F, (a: A) =>
  * @function
  * @since 1.0.0
  */
+export function getFunctorComposition<F extends URIS3, G extends URIS, UF, LF>(
+  F: Functor3C<F, UF, LF>,
+  G: Functor1<G>
+): FunctorComposition3C1<F, G, UF, LF>
+export function getFunctorComposition<F extends URIS2, G extends URIS2, LG>(
+  F: Functor2<F>,
+  G: Functor2C<G, LG>
+): FunctorComposition22C<F, G, LG>
 export function getFunctorComposition<F extends URIS2, G extends URIS2>(
   F: Functor2<F>,
   G: Functor2<G>
 ): FunctorComposition22<F, G>
+export function getFunctorComposition<F extends URIS2, G extends URIS, LF>(
+  F: Functor2C<F, LF>,
+  G: Functor1<G>
+): FunctorComposition2C1<F, G, LF>
 export function getFunctorComposition<F extends URIS2, G extends URIS>(
   F: Functor2<F>,
   G: Functor1<G>
 ): FunctorComposition21<F, G>
+export function getFunctorComposition<F extends URIS, G extends URIS2, LG>(
+  F: Functor1<F>,
+  G: Functor2C<G, LG>
+): FunctorComposition12C<F, G, LG>
 export function getFunctorComposition<F extends URIS, G extends URIS2>(
   F: Functor1<F>,
   G: Functor2<G>
diff --git a/src/FunctorWithIndex.ts b/src/FunctorWithIndex.ts
new file mode 100644
index 00000000..620bd933
--- /dev/null
+++ b/src/FunctorWithIndex.ts
@@ -0,0 +1,165 @@
+import { HKT, Type, Type2, Type3, Type4, URIS, URIS2, URIS3, URIS4 } from './HKT'
+import {
+  Functor,
+  Functor1,
+  Functor2,
+  Functor3,
+  Functor4,
+  Functor2C,
+  Functor3C,
+  FunctorComposition,
+  FunctorComposition11,
+  FunctorComposition12,
+  FunctorComposition12C,
+  FunctorComposition21,
+  FunctorComposition2C1,
+  FunctorComposition22,
+  FunctorComposition22C,
+  FunctorComposition3C1,
+  getFunctorComposition
+} from './Functor'
+
+/**
+ * A `FunctorWithIndex` is a type constructor which supports a mapping operation `map`.
+ *
+ * `mapWithIndex` can be used to turn functions `i -> a -> b` into functions `f a -> f b` whose argument and return types use the type
+ * constructor `f` to represent some computational context.
+ *
+ * Instances must satisfy the following laws:
+ *
+ * 1. Identity: `F.mapWithIndex(fa, (_i, a) => a) = fa`
+ * 2. Composition: `F.mapWithIndex(fa, (_i, a) => bc(ab(a))) = F.mapWithIndex(F.mapWithIndex(fa, ab), bc)`
+ * @typeclass
+ * @since 1.12.0
+ */
+
+export interface FunctorWithIndex<F, I> extends Functor<F> {
+  readonly mapWithIndex: <A, B>(fa: HKT<F, A>, f: (i: I, a: A) => B) => HKT<F, B>
+}
+
+export interface FunctorWithIndex1<F extends URIS, I> extends Functor1<F> {
+  readonly mapWithIndex: <A, B>(fa: Type<F, A>, f: (i: I, a: A) => B) => Type<F, B>
+}
+
+export interface FunctorWithIndex2<F extends URIS2, I> extends Functor2<F> {
+  readonly mapWithIndex: <L, A, B>(fa: Type2<F, L, A>, f: (i: I, a: A) => B) => Type2<F, L, B>
+}
+
+export interface FunctorWithIndex3<F extends URIS3, I> extends Functor3<F> {
+  readonly mapWithIndex: <U, L, A, B>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => B) => Type3<F, U, L, B>
+}
+
+export interface FunctorWithIndex4<F extends URIS4, I> extends Functor4<F> {
+  readonly mapWithIndex: <X, U, L, A, B>(fa: Type4<F, X, U, L, A>, f: (i: I, a: A) => B) => Type4<F, X, U, L, B>
+}
+
+export interface FunctorWithIndex2C<F extends URIS2, I, L> extends Functor2C<F, L> {
+  readonly mapWithIndex: <A, B>(fa: Type2<F, L, A>, f: (i: I, a: A) => B) => Type2<F, L, B>
+}
+
+export interface FunctorWithIndex3C<F extends URIS3, I, U, L> extends Functor3C<F, U, L> {
+  readonly mapWithIndex: <A, B>(fa: Type3<F, U, L, A>, f: (i: I, a: A) => B) => Type3<F, U, L, B>
+}
+
+export interface FunctorWithIndexComposition<F, FI, G, GI> extends FunctorComposition<F, G> {
+  readonly mapWithIndex: <A, B>(fga: HKT<F, HKT<G, A>>, f: (i: [FI, GI], a: A) => B) => HKT<F, HKT<G, B>>
+}
+
+export interface FunctorWithIndexComposition11<F extends URIS, FI, G extends URIS, GI>
+  extends FunctorComposition11<F, G> {
+  readonly mapWithIndex: <A, B>(fa: Type<F, Type<G, A>>, f: (i: [FI, GI], a: A) => B) => Type<F, Type<G, B>>
+}
+
+export interface FunctorWithIndexComposition12<F extends URIS, FI, G extends URIS2, GI>
+  extends FunctorComposition12<F, G> {
+  readonly mapWithIndex: <L, A, B>(fa: Type<F, Type2<G, L, A>>, f: (i: [FI, GI], a: A) => B) => Type<F, Type2<G, L, B>>
+}
+
+export interface FunctorWithIndexComposition12C<F extends URIS, FI, G extends URIS2, GI, L>
+  extends FunctorComposition12C<F, G, L> {
+  readonly mapWithIndex: <A, B>(fa: Type<F, Type2<G, L, A>>, f: (i: [FI, GI], a: A) => B) => Type<F, Type2<G, L, B>>
+}
+
+export interface FunctorWithIndexComposition21<F extends URIS2, FI, G extends URIS, GI>
+  extends FunctorComposition21<F, G> {
+  readonly mapWithIndex: <L, A, B>(fa: Type2<F, L, Type<G, A>>, f: (i: [FI, GI], a: A) => B) => Type2<F, L, Type<G, B>>
+}
+
+export interface FunctorWithIndexComposition2C1<F extends URIS2, FI, G extends URIS, GI, L>
+  extends FunctorComposition2C1<F, G, L> {
+  readonly mapWithIndex: <A, B>(fa: Type2<F, L, Type<G, A>>, f: (i: [FI, GI], a: A) => B) => Type2<F, L, Type<G, B>>
+}
+
+export interface FunctorWithIndexComposition22<F extends URIS2, FI, G extends URIS2, GI>
+  extends FunctorComposition22<F, G> {
+  readonly mapWithIndex: <L, M, A, B>(
+    fa: Type2<F, L, Type2<G, M, A>>,
+    f: (i: [FI, GI], a: A) => B
+  ) => Type2<F, L, Type2<G, M, B>>
+}
+
+export interface FunctorWithIndexComposition22C<F extends URIS2, FI, G extends URIS2, GI, LG>
+  extends FunctorComposition22C<F, G, LG> {
+  readonly mapWithIndex: <L, A, B>(
+    fa: Type2<F, L, Type2<G, LG, A>>,
+    f: (i: [FI, GI], a: A) => B
+  ) => Type2<F, L, Type2<G, LG, B>>
+}
+
+export interface FunctorWithIndexComposition3C1<F extends URIS3, FI, G extends URIS, GI, UF, LF>
+  extends FunctorComposition3C1<F, G, UF, LF> {
+  readonly mapWithIndex: <A, B>(
+    fa: Type3<F, UF, LF, Type<G, A>>,
+    f: (i: [FI, GI], a: A) => B
+  ) => Type3<F, UF, LF, Type<G, B>>
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export function getFunctorWithIndexComposition<F extends URIS3, FI, G extends URIS, GI, U, L>(
+  F: FunctorWithIndex3C<F, FI, U, L>,
+  G: FunctorWithIndex1<G, FI>
+): FunctorWithIndexComposition3C1<F, FI, G, GI, U, L>
+export function getFunctorWithIndexComposition<F extends URIS2, FI, G extends URIS2, GI, L>(
+  F: FunctorWithIndex2<F, FI>,
+  G: FunctorWithIndex2C<G, FI, L>
+): FunctorWithIndexComposition22C<F, FI, G, GI, L>
+export function getFunctorWithIndexComposition<F extends URIS2, FI, G extends URIS2, GI>(
+  F: FunctorWithIndex2<F, FI>,
+  G: FunctorWithIndex2<G, FI>
+): FunctorWithIndexComposition22<F, FI, G, GI>
+export function getFunctorWithIndexComposition<F extends URIS2, FI, G extends URIS, GI, L>(
+  F: FunctorWithIndex2C<F, FI, L>,
+  G: FunctorWithIndex1<G, GI>
+): FunctorWithIndexComposition2C1<F, FI, G, GI, L>
+export function getFunctorWithIndexComposition<F extends URIS2, FI, G extends URIS, GI>(
+  F: FunctorWithIndex2<F, FI>,
+  G: FunctorWithIndex1<G, GI>
+): FunctorWithIndexComposition21<F, FI, G, GI>
+export function getFunctorWithIndexComposition<F extends URIS, FI, G extends URIS2, GI, L>(
+  F: FunctorWithIndex1<F, FI>,
+  G: FunctorWithIndex2C<G, GI, L>
+): FunctorWithIndexComposition12C<F, FI, G, GI, L>
+export function getFunctorWithIndexComposition<F extends URIS, FI, G extends URIS2, GI>(
+  F: FunctorWithIndex1<F, FI>,
+  G: FunctorWithIndex2<G, GI>
+): FunctorWithIndexComposition12<F, FI, G, GI>
+export function getFunctorWithIndexComposition<F extends URIS, FI, G extends URIS, GI>(
+  F: FunctorWithIndex1<F, FI>,
+  G: FunctorWithIndex1<G, GI>
+): FunctorWithIndexComposition11<F, FI, G, GI>
+export function getFunctorWithIndexComposition<F, FI, G, GI>(
+  F: FunctorWithIndex<F, FI>,
+  G: FunctorWithIndex<G, GI>
+): FunctorWithIndexComposition<F, FI, G, GI>
+export function getFunctorWithIndexComposition<F, FI, G, GI>(
+  F: FunctorWithIndex<F, FI>,
+  G: FunctorWithIndex<G, GI>
+): FunctorWithIndexComposition<F, FI, G, GI> {
+  return {
+    ...getFunctorComposition(F, G),
+    mapWithIndex: (fga, f) => F.mapWithIndex(fga, (fi, ga) => G.mapWithIndex(ga, (gi, a) => f([fi, gi], a)))
+  }
+}
diff --git a/src/NonEmptyArray.ts b/src/NonEmptyArray.ts
index c237e6ec..2730041f 100644
--- a/src/NonEmptyArray.ts
+++ b/src/NonEmptyArray.ts
@@ -22,7 +22,9 @@ import { none, Option, some } from './Option'
 import { Ord } from './Ord'
 import { fold, getJoinSemigroup, getMeetSemigroup, Semigroup } from './Semigroup'
 import { Setoid } from './Setoid'
-import { Traversable2v1 } from './Traversable2v'
+import { FunctorWithIndex1 } from './FunctorWithIndex'
+import { FoldableWithIndex1 } from './FoldableWithIndex'
+import { TraversableWithIndex1 } from './TraversableWithIndex'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -70,8 +72,6 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Functor}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -82,9 +82,11 @@ export class NonEmptyArray<A> {
     return new NonEmptyArray(f(this.head), this.tail.map(f))
   }
 
+  mapWithIndex<B>(f: (i: number, a: A) => B): NonEmptyArray<B> {
+    return new NonEmptyArray(f(0, this.head), array.mapWithIndex(this.tail, (i, a) => f(i + 1, a)))
+  }
+
   /**
-   * Instance-bound implementation of {@link Apply}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -111,8 +113,6 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Chain}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -125,8 +125,6 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Semigroup}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -139,8 +137,6 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Foldable}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -152,8 +148,27 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Extend}
-   *
+   * @since 1.12.0
+   */
+  reduceWithIndex<B>(b: B, f: (i: number, b: B, a: A) => B): B {
+    return array.reduceWithIndex(this.toArray(), b, f)
+  }
+
+  /**
+   * @since 1.12.0
+   */
+  foldr<B>(b: B, f: (a: A, b: B) => B): B {
+    return this.foldrWithIndex(b, (_, a, b) => f(a, b))
+  }
+
+  /**
+   * @since 1.12.0
+   */
+  foldrWithIndex<B>(b: B, f: (i: number, a: A, b: B) => B): B {
+    return f(0, this.head, this.tail.reduceRight((acc, a, i) => f(i + 1, a, acc), b))
+  }
+
+  /**
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    * import { fold, monoidSum } from 'fp-ts/lib/Monoid'
@@ -166,8 +181,6 @@ export class NonEmptyArray<A> {
   }
 
   /**
-   * Instance-bound implementation of {@link Comonad}
-   *
    * @example
    * import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'
    *
@@ -422,8 +435,16 @@ export class NonEmptyArray<A> {
   filter<B extends A>(predicate: Refinement<A, B>): Option<NonEmptyArray<B>>
   filter(predicate: Predicate<A>): Option<NonEmptyArray<A>>
   filter(predicate: Predicate<A>): Option<NonEmptyArray<A>> {
-    const t = this.tail.filter(predicate)
-    return predicate(this.head) ? some(new NonEmptyArray(this.head, t)) : fromArray(t)
+    return this.filterWithIndex((_, a) => predicate(a))
+  }
+
+  /**
+   * @function
+   * @since 1.12.0
+   */
+  filterWithIndex(predicate: (i: number, a: A) => boolean): Option<NonEmptyArray<A>> {
+    const t = array.filterWithIndex(this.tail, (i, a) => predicate(i + 1, a))
+    return predicate(0, this.head) ? some(new NonEmptyArray(this.head, t)) : fromArray(t)
   }
 }
 
@@ -444,6 +465,10 @@ const map = <A, B>(fa: NonEmptyArray<A>, f: (a: A) => B): NonEmptyArray<B> => {
   return fa.map(f)
 }
 
+const mapWithIndex = <A, B>(fa: NonEmptyArray<A>, f: (i: number, a: A) => B): NonEmptyArray<B> => {
+  return fa.mapWithIndex(f)
+}
+
 const of = <A>(a: A): NonEmptyArray<A> => {
   return new NonEmptyArray(a, [])
 }
@@ -535,7 +560,19 @@ const foldMap = <M>(M: Monoid<M>) => <A>(fa: NonEmptyArray<A>, f: (a: A) => M):
 }
 
 const foldr = <A, B>(fa: NonEmptyArray<A>, b: B, f: (a: A, b: B) => B): B => {
-  return f(fa.head, fa.tail.reduceRight((acc, a) => f(a, acc), b))
+  return fa.foldr(b, f)
+}
+
+const reduceWithIndex = <A, B>(fa: NonEmptyArray<A>, b: B, f: (i: number, b: B, a: A) => B): B => {
+  return fa.reduceWithIndex(b, f)
+}
+
+const foldMapWithIndex = <M>(M: Monoid<M>) => <A>(fa: NonEmptyArray<A>, f: (i: number, a: A) => M): M => {
+  return fa.tail.reduce((acc, a, i) => M.concat(acc, f(i + 1, a)), f(0, fa.head))
+}
+
+const foldrWithIndex = <A, B>(fa: NonEmptyArray<A>, b: B, f: (i: number, a: A, b: B) => B): B => {
+  return fa.foldrWithIndex(b, f)
 }
 
 const extend = <A, B>(fa: NonEmptyArray<A>, f: (fa: NonEmptyArray<A>) => B): NonEmptyArray<B> => {
@@ -549,12 +586,8 @@ const extract = <A>(fa: NonEmptyArray<A>): A => {
 function traverse<F>(
   F: Applicative<F>
 ): <A, B>(ta: NonEmptyArray<A>, f: (a: A) => HKT<F, B>) => HKT<F, NonEmptyArray<B>> {
-  const traverseF = array.traverse(F)
-  return <A, B>(ta: NonEmptyArray<A>, f: (a: A) => HKT<F, B>) => {
-    const fb = f(ta.head)
-    const fbs = traverseF(ta.tail, f)
-    return F.ap(F.map(fb, b => (bs: Array<B>) => new NonEmptyArray(b, bs)), fbs)
-  }
+  const traverseWithIndexF = traverseWithIndex(F)
+  return (ta, f) => traverseWithIndexF(ta, (_, a) => f(a))
 }
 
 function sequence<F>(F: Applicative<F>): <A>(ta: NonEmptyArray<HKT<F, A>>) => HKT<F, NonEmptyArray<A>> {
@@ -591,15 +624,32 @@ export const groupBy = <A>(as: Array<A>, f: (a: A) => string): { [key: string]:
   return r
 }
 
+const traverseWithIndex = <F>(
+  F: Applicative<F>
+): (<A, B>(ta: NonEmptyArray<A>, f: (i: number, a: A) => HKT<F, B>) => HKT<F, NonEmptyArray<B>>) => {
+  const traverseWithIndexF = array.traverseWithIndex(F)
+  return <A, B>(ta: NonEmptyArray<A>, f: (i: number, a: A) => HKT<F, B>) => {
+    const fb = f(0, ta.head)
+    const fbs = traverseWithIndexF(ta.tail, (i, a) => f(i + 1, a))
+    return F.ap(F.map(fb, b => (bs: Array<B>) => new NonEmptyArray(b, bs)), fbs)
+  }
+}
+
 /**
  * @instance
  * @since 1.0.0
  */
-export const nonEmptyArray: Monad1<URI> & Comonad1<URI> & Foldable2v1<URI> & Traversable2v1<URI> = {
+export const nonEmptyArray: Monad1<URI> &
+  Comonad1<URI> &
+  Foldable2v1<URI> &
+  TraversableWithIndex1<URI, number> &
+  FunctorWithIndex1<URI, number> &
+  FoldableWithIndex1<URI, number> = {
   URI,
   extend,
   extract,
   map,
+  mapWithIndex,
   of,
   ap,
   chain,
@@ -607,5 +657,9 @@ export const nonEmptyArray: Monad1<URI> & Comonad1<URI> & Foldable2v1<URI> & Tra
   foldMap,
   foldr,
   traverse,
-  sequence
+  sequence,
+  reduceWithIndex,
+  foldMapWithIndex,
+  foldrWithIndex,
+  traverseWithIndex
 }
diff --git a/src/Option.ts b/src/Option.ts
index e45c5cf6..e59ae7f0 100644
--- a/src/Option.ts
+++ b/src/Option.ts
@@ -134,6 +134,7 @@ export class None<A> {
   map<B>(f: (a: A) => B): Option<B> {
     return none
   }
+
   /**
    * Maps `f` over this `Option`'s value. If the value returned from `f` is null or undefined, returns `None`
    *
@@ -337,6 +338,7 @@ export class Some<A> {
   map<B>(f: (a: A) => B): Option<B> {
     return new Some(f(this.value))
   }
+
   mapNullable<B>(f: (a: A) => B | null | undefined): Option<B> {
     return fromNullable(f(this.value))
   }
diff --git a/src/Record.ts b/src/Record.ts
index ff5817ad..bde600cb 100644
--- a/src/Record.ts
+++ b/src/Record.ts
@@ -136,15 +136,7 @@ export const lookup = <A>(key: string, fa: Record<string, A>): Option<A> => {
 export function filter<A, B extends A>(fa: Record<string, A>, p: Refinement<A, B>): Record<string, B>
 export function filter<A>(fa: Record<string, A>, p: Predicate<A>): Record<string, A>
 export function filter<A>(fa: Record<string, A>, p: Predicate<A>): Record<string, A> {
-  const r: Record<string, A> = {}
-  const keys = Object.keys(fa)
-  for (const key of keys) {
-    const a = fa[key]
-    if (p(a)) {
-      r[key] = a
-    }
-  }
-  return r
+  return filterWithIndex(fa, (_, a) => p(a))
 }
 
 /**
@@ -208,39 +200,67 @@ export const map = <A, B>(fa: Record<string, A>, f: (a: A) => B): Record<string,
  * @since 1.10.0
  */
 export const reduce = <A, B>(fa: Record<string, A>, b: B, f: (b: B, a: A) => B): B => {
+  return reduceWithKey(fa, b, (_, b, a) => f(b, a))
+}
+
+/**
+ * @function
+ * @since 1.10.0
+ */
+export const foldMap = <M>(M: Monoid<M>): (<A>(fa: Record<string, A>, f: (a: A) => M) => M) => {
+  const foldMapWithKeyM = foldMapWithKey(M)
+  return (fa, f) => foldMapWithKeyM(fa, (_, a) => f(a))
+}
+
+/**
+ * @function
+ * @since 1.10.0
+ */
+export const foldr = <A, B>(fa: Record<string, A>, b: B, f: (a: A, b: B) => B): B => {
+  return foldrWithKey(fa, b, (_, a, b) => f(a, b))
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const reduceWithKey = <A, B>(fa: Record<string, A>, b: B, f: (k: string, b: B, a: A) => B): B => {
   let out: B = b
   const keys = Object.keys(fa).sort()
   const len = keys.length
   for (let i = 0; i < len; i++) {
-    out = f(out, fa[keys[i]])
+    const k = keys[i]
+    out = f(k, out, fa[k])
   }
   return out
 }
 
 /**
  * @function
- * @since 1.10.0
+ * @since 1.12.0
  */
-export const foldMap = <M>(M: Monoid<M>) => <A>(fa: Record<string, A>, f: (a: A) => M): M => {
+export const foldMapWithKey = <M>(M: Monoid<M>) => <A>(fa: Record<string, A>, f: (k: string, a: A) => M): M => {
   let out: M = M.empty
   const keys = Object.keys(fa).sort()
   const len = keys.length
   for (let i = 0; i < len; i++) {
-    out = M.concat(out, f(fa[keys[i]]))
+    const k = keys[i]
+    out = M.concat(out, f(k, fa[k]))
   }
   return out
 }
 
 /**
  * @function
- * @since 1.10.0
+ * @since 1.12.0
  */
-export const foldr = <A, B>(fa: Record<string, A>, b: B, f: (a: A, b: B) => B): B => {
+export const foldrWithKey = <A, B>(fa: Record<string, A>, b: B, f: (k: string, a: A, b: B) => B): B => {
   let out: B = b
   const keys = Object.keys(fa).sort()
   const len = keys.length
   for (let i = len - 1; i >= 0; i--) {
-    out = f(fa[keys[i]], out)
+    const k = keys[i]
+    out = f(k, fa[k], out)
   }
   return out
 }
@@ -361,21 +381,7 @@ export const partitionMap = <RL, RR, A>(
   fa: Record<string, A>,
   f: (a: A) => Either<RL, RR>
 ): Separated<Record<string, RL>, Record<string, RR>> => {
-  const left: Record<string, RL> = {}
-  const right: Record<string, RR> = {}
-  const keys = Object.keys(fa)
-  for (const key of keys) {
-    const e = f(fa[key])
-    if (e.isLeft()) {
-      left[key] = e.value
-    } else {
-      right[key] = e.value
-    }
-  }
-  return {
-    left,
-    right
-  }
+  return partitionMapWithIndex(fa, (_, a) => f(a))
 }
 
 /**
@@ -386,21 +392,7 @@ export const partition = <A>(
   fa: Record<string, A>,
   p: Predicate<A>
 ): Separated<Record<string, A>, Record<string, A>> => {
-  const left: Record<string, A> = {}
-  const right: Record<string, A> = {}
-  const keys = Object.keys(fa)
-  for (const key of keys) {
-    const a = fa[key]
-    if (p(a)) {
-      right[key] = a
-    } else {
-      left[key] = a
-    }
-  }
-  return {
-    left,
-    right
-  }
+  return partitionWithIndex(fa, (_, a) => p(a))
 }
 
 /**
@@ -511,13 +503,90 @@ export function wilt<F>(
  * @since 1.10.0
  */
 export const filterMap = <A, B>(fa: Record<string, A>, f: (a: A) => Option<B>): Record<string, B> => {
+  return filterMapWithIndex(fa, (_, a) => f(a))
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const partitionMapWithIndex = <RL, RR, A>(
+  fa: Record<string, A>,
+  f: (key: string, a: A) => Either<RL, RR>
+): Separated<Record<string, RL>, Record<string, RR>> => {
+  const left: Record<string, RL> = {}
+  const right: Record<string, RR> = {}
+  const keys = Object.keys(fa)
+  for (const key of keys) {
+    const e = f(key, fa[key])
+    if (e.isLeft()) {
+      left[key] = e.value
+    } else {
+      right[key] = e.value
+    }
+  }
+  return {
+    left,
+    right
+  }
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const partitionWithIndex = <A>(
+  fa: Record<string, A>,
+  p: (key: string, a: A) => boolean
+): Separated<Record<string, A>, Record<string, A>> => {
+  const left: Record<string, A> = {}
+  const right: Record<string, A> = {}
+  const keys = Object.keys(fa)
+  for (const key of keys) {
+    const a = fa[key]
+    if (p(key, a)) {
+      right[key] = a
+    } else {
+      left[key] = a
+    }
+  }
+  return {
+    left,
+    right
+  }
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const filterMapWithIndex = <A, B>(
+  fa: Record<string, A>,
+  f: (key: string, a: A) => Option<B>
+): Record<string, B> => {
   const r: Record<string, B> = {}
   const keys = Object.keys(fa)
   for (const key of keys) {
-    const optionB = f(fa[key])
+    const optionB = f(key, fa[key])
     if (optionB.isSome()) {
       r[key] = optionB.value
     }
   }
   return r
 }
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const filterWithIndex = <A>(fa: Record<string, A>, p: (key: string, a: A) => boolean): Record<string, A> => {
+  const r: Record<string, A> = {}
+  const keys = Object.keys(fa)
+  for (const key of keys) {
+    const a = fa[key]
+    if (p(key, a)) {
+      r[key] = a
+    }
+  }
+  return r
+}
diff --git a/src/Set.ts b/src/Set.ts
index c1267cb2..d0efefa8 100644
--- a/src/Set.ts
+++ b/src/Set.ts
@@ -3,8 +3,9 @@ import { Monoid } from './Monoid'
 import { Ord } from './Ord'
 import { Semigroup } from './Semigroup'
 import { Setoid } from './Setoid'
-import { Predicate, not, Refinement } from './function'
+import { Predicate, not, Refinement, identity } from './function'
 import { Separated } from './Compactable'
+import { Option } from './Option'
 
 /**
  * @function
@@ -214,13 +215,31 @@ export const partitionMap = <L, R>(SL: Setoid<L>, SR: Setoid<R>) => <A>(
 }
 
 /**
- * Form the set difference (`y` - `x`)
+ * Use {@link difference2v} instead
  * @function
  * @since 1.0.0
+ * @deprecated
  */
 export const difference = <A>(S: Setoid<A>): ((x: Set<A>, y: Set<A>) => Set<A>) => {
+  const d = difference2v(S)
+  return (x, y) => d(y, x)
+}
+
+/**
+ * Form the set difference (`x` - `y`)
+ *
+ * @example
+ * import { difference2v } from 'fp-ts/lib/Set'
+ * import { setoidNumber } from 'fp-ts/lib/Setoid'
+ *
+ * assert.deepEqual(difference2v(setoidNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+ *
+ * @function
+ * @since 1.12.0
+ */
+export const difference2v = <A>(S: Setoid<A>): ((x: Set<A>, y: Set<A>) => Set<A>) => {
   const has = member(S)
-  return (x, y) => filter(y, not(has(x)))
+  return (x, y) => filter(x, not(has(y)))
 }
 
 /**
@@ -306,3 +325,56 @@ export const fromArray = <A>(S: Setoid<A>) => (as: Array<A>): Set<A> => {
   }
   return r
 }
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const compact = <A>(S: Setoid<A>): ((fa: Set<Option<A>>) => Set<A>) => {
+  const filterMapS = filterMap(S)
+  return fa => filterMapS(fa, identity)
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const separate = <L, R>(SL: Setoid<L>, SR: Setoid<R>) => (fa: Set<Either<L, R>>): Separated<Set<L>, Set<R>> => {
+  const memberSL = member(SL)
+  const memberSR = member(SR)
+  const left: Set<L> = new Set()
+  const right: Set<R> = new Set()
+  const isMemberL = memberSL(left)
+  const isMemberR = memberSR(right)
+  fa.forEach(e => {
+    if (e.isLeft()) {
+      if (!isMemberL(e.value)) {
+        left.add(e.value)
+      }
+    } else {
+      if (!isMemberR(e.value)) {
+        right.add(e.value)
+      }
+    }
+  })
+  return { left, right }
+}
+
+/**
+ * @function
+ * @since 1.12.0
+ */
+export const filterMap = <B>(S: Setoid<B>): (<A>(fa: Set<A>, f: (a: A) => Option<B>) => Set<B>) => {
+  const memberS = member(S)
+  return (fa, f) => {
+    const r: Set<B> = new Set()
+    const isMember = memberS(r)
+    fa.forEach(a => {
+      const ob = f(a)
+      if (ob.isSome() && !isMember(ob.value)) {
+        r.add(ob.value)
+      }
+    })
+    return r
+  }
+}
diff --git a/src/StrMap.ts b/src/StrMap.ts
index e2918d71..473a6aff 100644
--- a/src/StrMap.ts
+++ b/src/StrMap.ts
@@ -1,18 +1,19 @@
 import { Applicative, Applicative1, Applicative2, Applicative3 } from './Applicative'
 import { Compactable1, Separated } from './Compactable'
 import { Either } from './Either'
-import { Filterable1 } from './Filterable'
+import { FilterableWithIndex1 } from './FilterableWithIndex'
 import { Foldable, Foldable1, Foldable2, Foldable3 } from './Foldable'
 import { Foldable2v1 } from './Foldable2v'
-import { Predicate, tuple, Refinement } from './function'
-import { Functor1 } from './Functor'
+import { FoldableWithIndex1 } from './FoldableWithIndex'
+import { Predicate, Refinement, tuple } from './function'
+import { FunctorWithIndex1 } from './FunctorWithIndex'
 import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 import { Monoid } from './Monoid'
 import { Option } from './Option'
 import * as R from './Record'
 import { getDictionarySemigroup, getLastSemigroup, Semigroup } from './Semigroup'
 import { Setoid } from './Setoid'
-import { Traversable2v1 } from './Traversable2v'
+import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable } from './Unfoldable'
 import { Witherable1 } from './Witherable'
 
@@ -28,6 +29,16 @@ export const URI = 'StrMap'
 
 export type URI = typeof URI
 
+const liftSeparated = <L, R>({
+  left,
+  right
+}: Separated<Record<string, L>, Record<string, R>>): Separated<StrMap<L>, StrMap<R>> => {
+  return {
+    left: new StrMap(left),
+    right: new StrMap(right)
+  }
+}
+
 /**
  * @data
  * @constructor StrMap
@@ -46,13 +57,79 @@ export class StrMap<A> {
   reduce<B>(b: B, f: (b: B, a: A) => B): B {
     return R.reduce(this.value, b, f)
   }
+  /**
+   * @since 1.12.0
+   */
+  foldr<B>(b: B, f: (a: A, b: B) => B): B {
+    return R.foldr(this.value, b, f)
+  }
+  /**
+   * @since 1.12.0
+   */
+  reduceWithKey<B>(b: B, f: (k: string, b: B, a: A) => B): B {
+    return R.reduceWithKey(this.value, b, f)
+  }
+  /**
+   * @since 1.12.0
+   */
+  foldrWithKey<B>(b: B, f: (k: string, a: A, b: B) => B): B {
+    return R.foldrWithKey(this.value, b, f)
+  }
   /**
    * @since 1.4.0
    */
   filter<B extends A>(p: Refinement<A, B>): StrMap<B>
   filter(p: Predicate<A>): StrMap<A>
   filter(p: Predicate<A>): StrMap<A> {
-    return new StrMap(R.filter(this.value, p))
+    return this.filterWithIndex((_, a) => p(a))
+  }
+  /**
+   * @since 1.12.0
+   */
+  filterMap<B>(f: (a: A) => Option<B>): StrMap<B> {
+    return this.filterMapWithIndex((_, a) => f(a))
+  }
+  /**
+   * @since 1.12.0
+   */
+  partition(p: Predicate<A>): Separated<StrMap<A>, StrMap<A>> {
+    return this.partitionWithIndex((_, a) => p(a))
+  }
+  /**
+   * @since 1.12.0
+   */
+  partitionMap<RL, RR>(f: (a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>> {
+    return this.partitionMapWithIndex((_, a) => f(a))
+  }
+  /**
+   * @since 1.12.0
+   */
+  separate<RL, RR>(this: StrMap<Either<RL, RR>>): Separated<StrMap<RL>, StrMap<RR>> {
+    return liftSeparated(R.separate(this.value))
+  }
+  /**
+   * @since 1.12.0
+   */
+  partitionMapWithIndex<RL, RR>(f: (i: string, a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>> {
+    return liftSeparated(R.partitionMapWithIndex(this.value, f))
+  }
+  /**
+   * @since 1.12.0
+   */
+  partitionWithIndex(p: (i: string, a: A) => boolean): Separated<StrMap<A>, StrMap<A>> {
+    return liftSeparated(R.partitionWithIndex(this.value, p))
+  }
+  /**
+   * @since 1.12.0
+   */
+  filterMapWithIndex<B>(f: (i: string, a: A) => Option<B>): StrMap<B> {
+    return new StrMap(R.filterMapWithIndex(this.value, f))
+  }
+  /**
+   * @since 1.12.0
+   */
+  filterWithIndex(p: (i: string, a: A) => boolean): StrMap<A> {
+    return new StrMap(R.filterWithIndex(this.value, p))
   }
 }
 
@@ -92,7 +169,20 @@ const foldMap = <M>(M: Monoid<M>): (<A>(fa: StrMap<A>, f: (a: A) => M) => M) =>
 }
 
 const foldr = <A, B>(fa: StrMap<A>, b: B, f: (a: A, b: B) => B): B => {
-  return R.foldr(fa.value, b, f)
+  return fa.foldr(b, f)
+}
+
+const reduceWithIndex = <A, B>(fa: StrMap<A>, b: B, f: (k: string, b: B, a: A) => B): B => {
+  return fa.reduceWithKey(b, f)
+}
+
+const foldMapWithIndex = <M>(M: Monoid<M>): (<A>(fa: StrMap<A>, f: (k: string, a: A) => M) => M) => {
+  const foldMapWithKey = R.foldMapWithKey(M)
+  return (fa, f) => foldMapWithKey(fa.value, f)
+}
+
+const foldrWithIndex = <A, B>(fa: StrMap<A>, b: B, f: (k: string, a: A, b: B) => B): B => {
+  return fa.foldrWithKey(b, f)
 }
 
 /**
@@ -262,7 +352,7 @@ export const pop = <A>(k: string, d: StrMap<A>): Option<[A, StrMap<A>]> => {
 }
 
 const filterMap = <A, B>(fa: StrMap<A>, f: (a: A) => Option<B>): StrMap<B> => {
-  return new StrMap(R.filterMap(fa.value, f))
+  return fa.filterMap(f)
 }
 
 const filter = <A>(fa: StrMap<A>, p: Predicate<A>): StrMap<A> => {
@@ -273,28 +363,16 @@ const compact = <A>(fa: StrMap<Option<A>>): StrMap<A> => {
   return new StrMap(R.compact(fa.value))
 }
 
-const partitionMap = <RL, RR, A>(fa: StrMap<A>, f: (a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>> => {
-  const { left, right } = R.partitionMap(fa.value, f)
-  return {
-    left: new StrMap(left),
-    right: new StrMap(right)
-  }
+const separate = <RL, RR>(fa: StrMap<Either<RL, RR>>): Separated<StrMap<RL>, StrMap<RR>> => {
+  return fa.separate()
 }
 
-const partition = <A>(fa: StrMap<A>, p: Predicate<A>): Separated<StrMap<A>, StrMap<A>> => {
-  const { left, right } = R.partition(fa.value, p)
-  return {
-    left: new StrMap(left),
-    right: new StrMap(right)
-  }
+const partitionMap = <RL, RR, A>(fa: StrMap<A>, f: (a: A) => Either<RL, RR>): Separated<StrMap<RL>, StrMap<RR>> => {
+  return fa.partitionMap(f)
 }
 
-const separate = <RL, RR>(fa: StrMap<Either<RL, RR>>): Separated<StrMap<RL>, StrMap<RR>> => {
-  const { left, right } = R.separate(fa.value)
-  return {
-    left: new StrMap(left),
-    right: new StrMap(right)
-  }
+const partition = <A>(fa: StrMap<A>, p: Predicate<A>): Separated<StrMap<A>, StrMap<A>> => {
+  return fa.partition(p)
 }
 
 const wither = <F>(F: Applicative<F>): (<A, B>(wa: StrMap<A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, StrMap<B>>) => {
@@ -309,16 +387,42 @@ const wilt = <F>(
   return (wa, f) => F.map(traverseF(wa, f), separate)
 }
 
+const mapWithIndex = <A, B>(fa: StrMap<A>, f: (i: string, a: A) => B): StrMap<B> => {
+  return fa.mapWithKey(f)
+}
+
+const traverseWithIndex = traverseWithKey
+
+const partitionMapWithIndex = <RL, RR, A>(
+  fa: StrMap<A>,
+  f: (i: string, a: A) => Either<RL, RR>
+): Separated<StrMap<RL>, StrMap<RR>> => {
+  return fa.partitionMapWithIndex(f)
+}
+
+const partitionWithIndex = <A>(fa: StrMap<A>, p: (i: string, a: A) => boolean): Separated<StrMap<A>, StrMap<A>> => {
+  return fa.partitionWithIndex(p)
+}
+
+const filterMapWithIndex = <A, B>(fa: StrMap<A>, f: (i: string, a: A) => Option<B>): StrMap<B> => {
+  return fa.filterMapWithIndex(f)
+}
+
+const filterWithIndex = <A>(fa: StrMap<A>, p: (i: string, a: A) => boolean): StrMap<A> => {
+  return fa.filterWithIndex(p)
+}
+
 /**
  * @instance
  * @since 1.0.0
  */
-export const strmap: Functor1<URI> &
+export const strmap: FunctorWithIndex1<URI, string> &
   Foldable2v1<URI> &
-  Traversable2v1<URI> &
+  TraversableWithIndex1<URI, string> &
   Compactable1<URI> &
-  Filterable1<URI> &
-  Witherable1<URI> = {
+  FilterableWithIndex1<URI, string> &
+  Witherable1<URI> &
+  FoldableWithIndex1<URI, string> = {
   URI,
   map,
   reduce,
@@ -333,5 +437,14 @@ export const strmap: Functor1<URI> &
   partition,
   partitionMap,
   wither,
-  wilt
+  wilt,
+  mapWithIndex,
+  reduceWithIndex,
+  foldMapWithIndex,
+  foldrWithIndex,
+  traverseWithIndex,
+  partitionMapWithIndex,
+  partitionWithIndex,
+  filterMapWithIndex,
+  filterWithIndex
 }
diff --git a/src/TaskEither.ts b/src/TaskEither.ts
index 35cce816..79921682 100644
--- a/src/TaskEither.ts
+++ b/src/TaskEither.ts
@@ -64,19 +64,33 @@ export class TaskEither<L, A> {
     return fb.ap(this)
   }
   /**
-   * Combine two effectful actions, keeping only the result of the first
+   * Combine two (parallel) effectful actions, keeping only the result of the first
    * @since 1.6.0
    */
   applyFirst<B>(fb: TaskEither<L, B>): TaskEither<L, A> {
     return fb.ap(this.map(constant))
   }
   /**
-   * Combine two effectful actions, keeping only the result of the second
+   * Combine two (parallel) effectful actions, keeping only the result of the second
    * @since 1.5.0
    */
   applySecond<B>(fb: TaskEither<L, B>): TaskEither<L, B> {
     return fb.ap(this.map<(b: B) => B>(constIdentity))
   }
+  /**
+   * Combine two (sequential) effectful actions, keeping only the result of the first
+   * @since 1.12.0
+   */
+  chainFirst<B>(fb: TaskEither<L, B>): TaskEither<L, A> {
+    return this.chain(a => fb.map(() => a))
+  }
+  /**
+   * Combine two (sequential) effectful actions, keeping only the result of the second
+   * @since 1.12.0
+   */
+  chainSecond<B>(fb: TaskEither<L, B>): TaskEither<L, B> {
+    return this.chain(() => fb)
+  }
   chain<B>(f: (a: A) => TaskEither<L, B>): TaskEither<L, B> {
     return new TaskEither(eitherTTask.chain(a => f(a).value, this.value))
   }
diff --git a/src/TraversableWithIndex.ts b/src/TraversableWithIndex.ts
new file mode 100644
index 00000000..0f11f9fc
--- /dev/null
+++ b/src/TraversableWithIndex.ts
@@ -0,0 +1,81 @@
+import { Applicative, Applicative1, Applicative2, Applicative2C, Applicative3, Applicative3C } from './Applicative'
+import { FoldableWithIndex, FoldableWithIndex1 } from './FoldableWithIndex'
+import { FunctorWithIndex, FunctorWithIndex1 } from './FunctorWithIndex'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { Traversable2v, Traversable2v1 } from './Traversable2v'
+
+/**
+ * A {@link Traversable} with an additional index.
+ * A `TraversableWithIndex` instance must be compatible with its {@link Traversable} instance
+ *
+ * ```ts
+ * traverse(F)(ta, f) = traverseWithIndex(F)(ta, (_, a) => f(a))
+ * ```
+ *
+ * with its {@link FoldableWithIndex} instance
+ *
+ * ```ts
+ * foldMapWithIndex(M)(ta, f) = traverseWithIndex(getApplicative(M))(ta, (i, a) => new Const(f(i, a))).value
+ * ```
+ *
+ * and with its {@link FunctorWithIndex} instance
+ *
+ * ```purescript
+ * mapWithIndex(ta, f) = traverseWithIndex(identity)(ta, (i, a) => new Identity(f(i, a))).value
+ * ```
+ *
+ * @typeclass
+ * @since 1.12.0
+ */
+export interface TraversableWithIndex<T, I> extends FunctorWithIndex<T, I>, FoldableWithIndex<T, I>, Traversable2v<T> {
+  readonly traverseWithIndex: TraverseWithIndex<T, I>
+}
+
+export interface TraversableWithIndex1<T extends URIS, I>
+  extends FunctorWithIndex1<T, I>,
+    FoldableWithIndex1<T, I>,
+    Traversable2v1<T> {
+  readonly traverseWithIndex: TraverseWithIndex1<T, I>
+}
+
+export interface TraverseWithIndex<T, I> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: HKT<T, A>,
+    f: (i: I, a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, HKT<T, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: HKT<T, A>,
+    f: (i: I, a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, HKT<T, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: HKT<T, A>,
+    f: (i: I, a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, HKT<T, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: HKT<T, A>,
+    f: (i: I, a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, HKT<T, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(ta: HKT<T, A>, f: (i: I, a: A) => Type<F, B>) => Type<F, HKT<T, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: HKT<T, A>, f: (i: I, a: A) => HKT<F, B>) => HKT<F, HKT<T, B>>
+}
+
+export interface TraverseWithIndex1<T extends URIS, I> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type<T, A>,
+    f: (i: I, a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type<T, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type<T, A>,
+    f: (i: I, a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type<T, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type<T, A>,
+    f: (i: I, a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type<T, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type<T, A>,
+    f: (i: I, a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type<T, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(ta: Type<T, A>, f: (i: I, a: A) => Type<F, B>) => Type<F, Type<T, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type<T, A>, f: (i: I, a: A) => HKT<F, B>) => HKT<F, Type<T, B>>
+}
diff --git a/src/index.ts b/src/index.ts
index bfe6abb8..eeb2c71c 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -52,16 +52,24 @@ import * as extend from './Extend'
 export { extend }
 import * as field from './Field'
 export { field }
+import * as filterable from './Filterable'
+export { filterable }
+import * as filterableWithIndex from './FilterableWithIndex'
+export { filterableWithIndex }
 import * as foldable from './Foldable'
 export { foldable }
 import * as foldable2v from './Foldable2v'
 export { foldable2v }
+import * as foldableWithIndex from './FoldableWithIndex'
+export { foldableWithIndex }
 import * as free from './Free'
 export { free }
 import * as function_ from './function'
 export { function_ as function }
 import * as functor from './Functor'
 export { functor }
+import * as functorWithIndex from './FunctorWithIndex'
+export { functorWithIndex }
 import * as heytingAlgebra from './HeytingAlgebra'
 export { heytingAlgebra }
 import * as hkt from './HKT'
@@ -156,6 +164,8 @@ import * as traversable from './Traversable'
 export { traversable }
 import * as traversable2v from './Traversable2v'
 export { traversable2v }
+import * as traversableWithIndex from './TraversableWithIndex'
+export { traversableWithIndex }
 import * as tree from './Tree'
 export { tree }
 import * as tuple from './Tuple'
@@ -168,8 +178,6 @@ import * as writer from './Writer'
 export { writer }
 import * as compactable from './Compactable'
 export { compactable }
-import * as filterable from './Filterable'
-export { filterable }
 import * as witherable from './Witherable'
 export { witherable }
 import * as zipper from './Zipper'


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index c008a8d4..8c2d0fdd 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -56,7 +56,11 @@ import {
   replicate,
   findLastIndex,
   zipWith,
-  comprehension
+  comprehension,
+  partition,
+  union,
+  intersection,
+  difference
 } from '../src/Array'
 import { left, right } from '../src/Either'
 import { fold as foldMonoid, monoidSum, monoidString } from '../src/Monoid'
@@ -66,6 +70,7 @@ import { contramap, getArraySetoid, setoidBoolean, setoidNumber, setoidString, S
 import { identity, tuple, constTrue } from '../src/function'
 import * as I from '../src/Identity'
 import * as F from '../src/Foldable'
+import * as C from '../src/Const'
 
 const p = (n: number) => n > 2
 
@@ -357,6 +362,10 @@ describe('Array', () => {
     assert.deepEqual(array.map([1, 2, 3], n => n * 2), [2, 4, 6])
   })
 
+  it('mapWithIndex', () => {
+    assert.deepEqual(array.mapWithIndex([1, 2, 3], (i, n) => n + i), [1, 3, 5])
+  })
+
   it('ap', () => {
     assert.deepEqual(array.ap([(n: number) => n * 2, (n: number) => n + 1], [1, 2, 3]), [2, 4, 6, 2, 3, 4])
   })
@@ -545,6 +554,10 @@ describe('Array', () => {
     assert.deepEqual(y, [some(3), some(1)])
   })
 
+  it('filterWithIndex', () => {
+    assert.deepEqual(array.filterWithIndex(['a', 'b', 'c'], n => n % 2 === 0), ['a', 'c'])
+  })
+
   it('filterMap/mapOption', () => {
     const f = (n: number) => (n % 2 === 0 ? none : some(n))
     assert.deepEqual(mapOption(as, f), [1, 3])
@@ -563,6 +576,11 @@ describe('Array', () => {
   it('partition', () => {
     assert.deepEqual(array.partition([], p), { left: [], right: [] })
     assert.deepEqual(array.partition([1, 3], p), { left: [1], right: [3] })
+    // refinements
+    const xs: Array<string | number> = ['a', 'b', 1]
+    const isNumber = (x: string | number): x is number => typeof x === 'number'
+    const actual = partition(xs, isNumber)
+    assert.deepEqual(actual, { left: ['a', 'b'], right: [1] })
   })
 
   it('wither', () => {
@@ -646,4 +664,57 @@ describe('Array', () => {
       [3, 'b']
     ])
   })
+
+  it('reduceWithIndex', () => {
+    assert.deepEqual(array.reduceWithIndex(['a', 'b'], '', (i, b, a) => b + i + a), '0a1b')
+  })
+
+  it('foldMapWithIndex', () => {
+    assert.deepEqual(array.foldMapWithIndex(monoidString)(['a', 'b'], (i, a) => i + a), '0a1b')
+  })
+
+  it('foldrWithIndex', () => {
+    assert.deepEqual(array.foldrWithIndex(['a', 'b'], '', (i, a, b) => b + i + a), '1b0a')
+  })
+
+  it('traverseWithIndex', () => {
+    const ta = ['a', 'bb']
+    assert.deepEqual(
+      array.traverseWithIndex(option)(ta, (i, s) => (s.length >= 1 ? some(s + i) : none)),
+      some(['a0', 'bb1'])
+    )
+    assert.deepEqual(array.traverseWithIndex(option)(ta, (i, s) => (s.length > 1 ? some(s + i) : none)), none)
+
+    // FoldableWithIndex compatibility
+    const M = monoidString
+    const f = (i: number, s: string) => s + i
+    assert.deepEqual(
+      array.foldMapWithIndex(M)(ta, f),
+      array.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const(f(i, a))).value
+    )
+
+    // FunctorWithIndex compatibility
+    assert.deepEqual(
+      array.mapWithIndex(ta, f),
+      array.traverseWithIndex(I.identity)(ta, (i, a) => new I.Identity(f(i, a))).value
+    )
+  })
+
+  it('union', () => {
+    assert.deepEqual(union(setoidNumber)([1, 2], [3, 4]), [1, 2, 3, 4])
+    assert.deepEqual(union(setoidNumber)([1, 2], [2, 3]), [1, 2, 3])
+    assert.deepEqual(union(setoidNumber)([1, 2], [1, 2]), [1, 2])
+  })
+
+  it('intersection', () => {
+    assert.deepEqual(intersection(setoidNumber)([1, 2], [3, 4]), [])
+    assert.deepEqual(intersection(setoidNumber)([1, 2], [2, 3]), [2])
+    assert.deepEqual(intersection(setoidNumber)([1, 2], [1, 2]), [1, 2])
+  })
+
+  it('difference', () => {
+    assert.deepEqual(difference(setoidNumber)([1, 2], [3, 4]), [1, 2])
+    assert.deepEqual(difference(setoidNumber)([1, 2], [2, 3]), [1])
+    assert.deepEqual(difference(setoidNumber)([1, 2], [1, 2]), [])
+  })
 })
diff --git a/test/Compactable.ts b/test/Compactable.ts
new file mode 100644
index 00000000..1325e298
--- /dev/null
+++ b/test/Compactable.ts
@@ -0,0 +1,16 @@
+import * as assert from 'assert'
+import { array } from '../src/Array'
+import { getCompactableComposition } from '../src/Compactable'
+import { none, some } from '../src/Option'
+import { left, right } from '../src/Either'
+
+describe('Compactable', () => {
+  it('getCompactableComposition', () => {
+    const C = getCompactableComposition(array, array)
+    assert.deepEqual(C.compact([[some(1), none], [none, some(2)]]), [[1], [2]])
+    assert.deepEqual(C.separate([[left('a'), right(1)], [right(2), left('b')]]), {
+      left: [['a'], ['b']],
+      right: [[1], [2]]
+    })
+  })
+})
diff --git a/test/Filterable.ts b/test/Filterable.ts
new file mode 100644
index 00000000..4881d7b9
--- /dev/null
+++ b/test/Filterable.ts
@@ -0,0 +1,30 @@
+import * as assert from 'assert'
+import { array } from '../src/Array'
+import { getFilterableComposition } from '../src/Filterable'
+import { some, none } from '../src/Option'
+import { right, left } from '../src/Either'
+
+describe('Filterable', () => {
+  it('getFilterableComposition', () => {
+    const F = getFilterableComposition(array, array)
+    assert.deepEqual(F.filter([[1, 2], [3, 4]], a => a > 1), [[2], [3, 4]])
+
+    assert.deepEqual(F.filterMap([['a', 'bb'], ['ccc', 'dddd']], a => (a.length > 1 ? some(a.length) : none)), [
+      [2],
+      [3, 4]
+    ])
+
+    assert.deepEqual(F.partition([['a', 'bb'], ['ccc', 'dddd']], a => a.length % 2 === 0), {
+      left: [['a'], ['ccc']],
+      right: [['bb'], ['dddd']]
+    })
+
+    assert.deepEqual(
+      F.partitionMap([['a', 'bb'], ['ccc', 'dddd']], a => (a.length % 2 === 0 ? right(a.length) : left(a))),
+      {
+        left: [['a'], ['ccc']],
+        right: [[2], [4]]
+      }
+    )
+  })
+})
diff --git a/test/FoldableWithIndex.ts b/test/FoldableWithIndex.ts
new file mode 100644
index 00000000..4b53aae3
--- /dev/null
+++ b/test/FoldableWithIndex.ts
@@ -0,0 +1,23 @@
+import * as assert from 'assert'
+import { array } from '../src/Array'
+import { getFoldableWithIndexComposition } from '../src/FoldableWithIndex'
+import { monoidString } from '../src/Monoid'
+
+describe('FoldableWithIndex', () => {
+  it('getFoldableWithIndexComposition', () => {
+    const arrayOfArray = getFoldableWithIndexComposition(array, array)
+    const fa = [['a', 'b'], ['c', 'd']]
+
+    assert.deepEqual(
+      arrayOfArray.reduceWithIndex(fa, '', ([i, j]: [number, number], b: string, a: string) => b + a + i + j),
+      'a00b01c10d11'
+    )
+
+    assert.deepEqual(arrayOfArray.foldMapWithIndex(monoidString)(fa, ([i, j], a) => a + i + j), 'a00b01c10d11')
+
+    assert.deepEqual(
+      arrayOfArray.foldrWithIndex(fa, '', ([i, j]: [number, number], a: string, b: string) => b + a + i + j),
+      'd11c10b01a00'
+    )
+  })
+})
diff --git a/test/FunctorWithIndex.ts b/test/FunctorWithIndex.ts
new file mode 100644
index 00000000..03fda9b0
--- /dev/null
+++ b/test/FunctorWithIndex.ts
@@ -0,0 +1,11 @@
+import * as assert from 'assert'
+import { array } from '../src/Array'
+import { getFunctorWithIndexComposition } from '../src/FunctorWithIndex'
+
+describe('FunctorWithIndex', () => {
+  it('getFunctorComposition', () => {
+    const arrayOfArray = getFunctorWithIndexComposition(array, array)
+    const f = ([i, j]: [number, number], a: string) => a + i + j
+    assert.deepEqual(arrayOfArray.mapWithIndex([['a', 'b'], ['c', 'd']], f), [['a00', 'b01'], ['c10', 'd11']])
+  })
+})
diff --git a/test/NonEmptyArray.ts b/test/NonEmptyArray.ts
index 2e0838d7..64b8f3fe 100644
--- a/test/NonEmptyArray.ts
+++ b/test/NonEmptyArray.ts
@@ -6,6 +6,8 @@ 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'
 
 describe('NonEmptyArray', () => {
   it('concat', () => {
@@ -21,6 +23,13 @@ describe('NonEmptyArray', () => {
     assert.deepEqual(nonEmptyArray.map(x, double).toArray(), [2, 4])
   })
 
+  it('mapWithIndex', () => {
+    const x = new NonEmptyArray(1, [2])
+    const add = (i: number, n: number) => n + i
+    assert.deepEqual(x.mapWithIndex(add).toArray(), [1, 3])
+    assert.deepEqual(nonEmptyArray.mapWithIndex(x, add).toArray(), [1, 3])
+  })
+
   it('ap', () => {
     assert.deepEqual(nonEmptyArray.of(1), new NonEmptyArray(1, []))
   })
@@ -276,4 +285,47 @@ describe('NonEmptyArray', () => {
     const actual2 = new NonEmptyArray(some(3), [none, some(1)]).filter(isSome)
     assert.deepEqual(actual2, some(new NonEmptyArray(some(3), [some(1)])))
   })
+
+  it('filterWithIndex', () => {
+    assert.deepEqual(new NonEmptyArray(1, [2, 3]).filterWithIndex(i => i % 2 === 0), some(new NonEmptyArray(1, [3])))
+    assert.deepEqual(new NonEmptyArray(1, [2, 3]).filterWithIndex((i, a) => i % 2 === 1 && a > 2), none)
+  })
+
+  it('reduceWithIndex', () => {
+    assert.deepEqual(nonEmptyArray.reduceWithIndex(new NonEmptyArray('a', ['b']), '', (i, b, a) => b + i + a), '0a1b')
+  })
+
+  it('foldMapWithIndex', () => {
+    assert.deepEqual(
+      nonEmptyArray.foldMapWithIndex(monoidString)(new NonEmptyArray('a', ['b']), (i, a) => i + a),
+      '0a1b'
+    )
+  })
+
+  it('foldrWithIndex', () => {
+    assert.deepEqual(nonEmptyArray.foldrWithIndex(new NonEmptyArray('a', ['b']), '', (i, a, b) => b + i + a), '1b0a')
+  })
+
+  it('traverseWithIndex', () => {
+    const ta = new NonEmptyArray('a', ['bb'])
+    assert.deepEqual(
+      nonEmptyArray.traverseWithIndex(option)(ta, (i, s) => (s.length >= 1 ? some(s + i) : none)),
+      some(new NonEmptyArray('a0', ['bb1']))
+    )
+    assert.deepEqual(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) => s + i
+    assert.deepEqual(
+      nonEmptyArray.foldMapWithIndex(M)(ta, f),
+      nonEmptyArray.traverseWithIndex(C.getApplicative(M))(ta, (i, a) => new C.Const(f(i, a))).value
+    )
+
+    // FunctorWithIndex compatibility
+    assert.deepEqual(
+      nonEmptyArray.mapWithIndex(ta, f),
+      nonEmptyArray.traverseWithIndex(I.identity)(ta, (i, a) => new I.Identity(f(i, a))).value
+    )
+  })
 })
diff --git a/test/Record.ts b/test/Record.ts
index 89ecd872..ef8de8bd 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -185,4 +185,21 @@ describe('Record', () => {
     assert.deepEqual(wiltIdentity({}, f), new I.Identity({ left: {}, right: {} }))
     assert.deepEqual(wiltIdentity({ a: 1, b: 3 }, f), new I.Identity({ left: { a: 0 }, right: { b: 4 } }))
   })
+
+  it('reduceWithKey', () => {
+    const d1 = { k1: 'a', k2: 'b' }
+    assert.strictEqual(R.reduceWithKey(d1, '', (k, b, a) => b + k + a), 'k1ak2b')
+    const d2 = { k2: 'b', k1: 'a' }
+    assert.strictEqual(R.reduceWithKey(d2, '', (k, b, a) => b + k + a), 'k1ak2b')
+  })
+
+  it('foldMapWithKey', () => {
+    const x1 = { k1: 'a', k2: 'b' }
+    assert.strictEqual(R.foldMapWithKey(monoidString)(x1, (k, a) => k + a), 'k1ak2b')
+  })
+
+  it('foldrWithKey', () => {
+    const x1 = { k1: 'a', k2: 'b' }
+    assert.strictEqual(R.foldrWithKey(x1, '', (k, a, b) => b + k + a), 'k2bk1a')
+  })
 })
diff --git a/test/Set.ts b/test/Set.ts
index 4bb0a084..9f40090f 100644
--- a/test/Set.ts
+++ b/test/Set.ts
@@ -22,9 +22,14 @@ import {
   some,
   subset,
   toArray,
-  union
+  union,
+  difference2v,
+  compact,
+  separate,
+  filterMap
 } from '../src/Set'
-import { Setoid, setoidNumber, setoidString, getRecordSetoid } from '../src/Setoid'
+import { Setoid, setoidNumber, setoidString, getRecordSetoid, contramap } from '../src/Setoid'
+import { none, some as optionSome } from '../src/Option'
 
 const gte2 = (n: number) => n >= 2
 
@@ -163,6 +168,10 @@ describe('Set', () => {
     assert.deepEqual(difference(setoidNumber)(new Set([1, 2]), new Set([1, 3])), new Set([3]))
   })
 
+  it('difference2v', () => {
+    assert.deepEqual(difference2v(setoidNumber)(new Set([1, 2]), new Set([1, 3])), new Set([2]))
+  })
+
   it('reduce', () => {
     assert.deepEqual(reduce(ordNumber)(new Set([1, 2, 3]), '', (b, a) => b + a), '123')
     assert.deepEqual(reduce(ordNumber)(new Set([3, 2, 1]), '', (b, a) => b + a), '123')
@@ -192,4 +201,54 @@ describe('Set', () => {
 
     assert.deepEqual(fromArray(fooSetoid)(['a', 'a', 'b'].map(foo)), new Set(['a', 'b'].map(foo)))
   })
+
+  it('compact', () => {
+    assert.deepEqual(compact(setoidNumber)(new Set([optionSome(1), none, optionSome(2)])), new Set([1, 2]))
+    type R = { id: string }
+    const S: Setoid<R> = contramap(x => x.id, setoidString)
+    assert.deepEqual(
+      compact(S)(new Set([optionSome({ id: 'a' }), none, optionSome({ id: 'a' })])),
+      new Set([{ id: 'a' }])
+    )
+  })
+
+  it('separate', () => {
+    assert.deepEqual(
+      separate(setoidString, setoidNumber)(
+        new Set([right<string, number>(1), left<string, number>('a'), right<string, number>(2)])
+      ),
+      {
+        left: new Set(['a']),
+        right: new Set([1, 2])
+      }
+    )
+    type L = { error: string }
+    type R = { id: string }
+    const SL: Setoid<L> = contramap(x => x.error, setoidString)
+    const SR: Setoid<R> = contramap(x => x.id, setoidString)
+    assert.deepEqual(
+      separate(SL, SR)(
+        new Set([
+          right<L, R>({ id: 'a' }),
+          left<L, R>({ error: 'error' }),
+          right<L, R>({ id: 'a' }),
+          left<L, R>({ error: 'error' })
+        ])
+      ),
+      {
+        left: new Set([{ error: 'error' }]),
+        right: new Set([{ id: 'a' }])
+      }
+    )
+  })
+
+  it('filterMap', () => {
+    assert.deepEqual(
+      filterMap(setoidNumber)(new Set(['a', 'bb', 'ccc']), s => (s.length > 1 ? optionSome(s.length) : none)),
+      new Set([2, 3])
+    )
+    type R = { id: string }
+    const S: Setoid<R> = contramap(x => x.id, setoidString)
+    assert.deepEqual(filterMap(S)(new Set([{ id: 'a' }, { id: 'a' }]), optionSome), new Set([{ id: 'a' }]))
+  })
 })
diff --git a/test/StrMap.ts b/test/StrMap.ts
index d9670c80..2ba7e63b 100644
--- a/test/StrMap.ts
+++ b/test/StrMap.ts
@@ -136,6 +136,7 @@ describe('StrMap', () => {
 
   it('mapWithKey', () => {
     assert.deepEqual(new StrMap({ aa: 1 }).mapWithKey((k, a) => a + k.length), new StrMap({ aa: 3 }))
+    assert.deepEqual(strmap.mapWithIndex(new StrMap({ aa: 1 }), (k, a) => a + k.length), new StrMap({ aa: 3 }))
   })
 
   it('traverseWithKey', () => {
@@ -197,12 +198,25 @@ describe('StrMap', () => {
     assert.deepEqual(actual, new StrMap({ a: 1 }))
   })
 
+  it('filterWithIndex', () => {
+    assert.deepEqual(strmap.filterWithIndex(new StrMap({ a: 'a', b: 'b' }), k => k === 'a'), new StrMap({ a: 'a' }))
+  })
+
   it('filterMap', () => {
     const f = (n: number) => (p(n) ? some(n + 1) : none)
     assert.deepEqual(strmap.filterMap(new StrMap<number>({}), f), new StrMap({}))
     assert.deepEqual(strmap.filterMap(new StrMap({ a: 1, b: 3 }), f), new StrMap({ b: 4 }))
   })
 
+  it('filterMapWithIndex', () => {
+    assert.deepEqual(
+      strmap.filterMapWithIndex(new StrMap({ a: 'a', b: 'b' }), (k, a) => (k === 'a' ? some(a.length) : none)),
+      new StrMap({
+        a: 1
+      })
+    )
+  })
+
   it('partition', () => {
     assert.deepEqual(strmap.partition(new StrMap<number>({}), p), { left: new StrMap({}), right: new StrMap({}) })
     assert.deepEqual(strmap.partition(new StrMap<number>({ a: 1, b: 3 }), p), {
@@ -211,6 +225,13 @@ describe('StrMap', () => {
     })
   })
 
+  it('partitionWithIndex', () => {
+    assert.deepEqual(strmap.partitionWithIndex(new StrMap<string>({ a: 'a', b: 'b' }), k => k === 'a'), {
+      left: new StrMap({ b: 'b' }),
+      right: new StrMap({ a: 'a' })
+    })
+  })
+
   it('partitionMap', () => {
     const f = (n: number) => (p(n) ? right(n + 1) : left(n - 1))
     assert.deepEqual(strmap.partitionMap(new StrMap<number>({}), f), { left: new StrMap({}), right: new StrMap({}) })
@@ -220,6 +241,19 @@ describe('StrMap', () => {
     })
   })
 
+  it('partitionMapWithIndex', () => {
+    assert.deepEqual(
+      strmap.partitionMapWithIndex(
+        new StrMap<string>({ a: 'a', b: 'b' }),
+        (k, a) => (k === 'a' ? right(a.length) : left(a))
+      ),
+      {
+        left: new StrMap({ b: 'b' }),
+        right: new StrMap({ a: 1 })
+      }
+    )
+  })
+
   it('wither', () => {
     const witherIdentity = strmap.wither(I.identity)
     const f = (n: number) => new I.Identity(p(n) ? some(n + 1) : none)
@@ -251,4 +285,21 @@ describe('StrMap', () => {
   it('collect', () => {
     assert.deepEqual(collect(new StrMap({ b: 1, a: 2 }), identity), ['a', 'b'])
   })
+
+  it('reduceWithKey', () => {
+    const d1 = new StrMap({ k1: 'a', k2: 'b' })
+    assert.strictEqual(strmap.reduceWithIndex(d1, '', (k, b, a) => b + k + a), 'k1ak2b')
+    const d2 = new StrMap({ k2: 'b', k1: 'a' })
+    assert.strictEqual(strmap.reduceWithIndex(d2, '', (k, b, a) => b + k + a), 'k1ak2b')
+  })
+
+  it('foldMapWithKey', () => {
+    const x1 = new StrMap({ k1: 'a', k2: 'b' })
+    assert.strictEqual(strmap.foldMapWithIndex(monoidString)(x1, (k, a) => k + a), 'k1ak2b')
+  })
+
+  it('foldrWithKey', () => {
+    const x1 = new StrMap({ k1: 'a', k2: 'b' })
+    assert.strictEqual(strmap.foldrWithIndex(x1, '', (k, a, b) => b + k + a), 'k2bk1a')
+  })
 })
diff --git a/test/TaskEither.ts b/test/TaskEither.ts
index 7ce3957f..a0d187df 100644
--- a/test/TaskEither.ts
+++ b/test/TaskEither.ts
@@ -208,10 +208,23 @@ describe('TaskEither', () => {
 
   it('applySecond', () => {
     const log: Array<string> = []
-    const append = (message: string): TaskEither<string, number> =>
-      right(new Task(() => Promise.resolve(log.push(message))))
-    return append('a')
-      .applySecond(append('b'))
+    const append = (message: string, millis: number): TaskEither<string, number> =>
+      right(delay(millis, undefined).map(() => log.push(message)))
+    return append('a', 10)
+      .applySecond(append('b', 0))
+      .run()
+      .then(e => {
+        assert.deepEqual(e, eitherRight(1))
+        assert.deepEqual(log, ['b', 'a'])
+      })
+  })
+
+  it('ChainSecond', () => {
+    const log: Array<string> = []
+    const append = (message: string, millis: number): TaskEither<string, number> =>
+      right(delay(millis, undefined).map(() => log.push(message)))
+    return append('a', 10)
+      .chainSecond(append('b', 0))
       .run()
       .then(e => {
         assert.deepEqual(e, eitherRight(2))
@@ -297,10 +310,23 @@ describe('TaskEither', () => {
 
   it('applyFirst', () => {
     const log: Array<string> = []
-    const append = (message: string): TaskEither<string, number> =>
-      right(new Task(() => Promise.resolve(log.push(message))))
-    return append('a')
-      .applyFirst(append('b'))
+    const append = (message: string, millis: number): TaskEither<string, number> =>
+      right(delay(millis, undefined).map(() => log.push(message)))
+    return append('a', 10)
+      .applyFirst(append('b', 0))
+      .run()
+      .then(e => {
+        assert.deepEqual(e, eitherRight(2))
+        assert.deepEqual(log, ['b', 'a'])
+      })
+  })
+
+  it('chainFirst', () => {
+    const log: Array<string> = []
+    const append = (message: string, millis: number): TaskEither<string, number> =>
+      right(delay(millis, undefined).map(() => log.push(message)))
+    return append('a', 10)
+      .chainFirst(append('b', 0))
       .run()
       .then(e => {
         assert.deepEqual(e, eitherRight(1))