Repository: gcanti/fp-ts
Pull request #500 (2018-06-27 05:59:02)

Polish: add `forin` rule to tslint


Patch:
diff --git a/docs-generator/domain.ts b/docs-generator/domain.ts
index 5366ea8b..c2acd7f0 100644
--- a/docs-generator/domain.ts
+++ b/docs-generator/domain.ts
@@ -7,7 +7,8 @@ export class Method {
     readonly signature: string,
     readonly description: Option<string>,
     readonly since: string,
-    readonly example: Option<string>
+    readonly example: Option<string>,
+    readonly deprecated: boolean
   ) {}
 }
 
@@ -40,7 +41,8 @@ export class Func {
     readonly description: Option<string>,
     readonly isAlias: boolean,
     readonly since: string,
-    readonly example: Option<string>
+    readonly example: Option<string>,
+    readonly deprecated: boolean
   ) {}
 }
 
diff --git a/docs-generator/markdown.ts b/docs-generator/markdown.ts
index 4da78d79..ace1da47 100644
--- a/docs-generator/markdown.ts
+++ b/docs-generator/markdown.ts
@@ -29,6 +29,7 @@ export const code = (code: string) => '`' + code + '`'
 export const link = (text: string, href: string) => `[${text}](${href})`
 export const ts = fence('ts')
 export const italic = (code: string) => '*' + code + '*'
+export const strike = (text: string) => '~~' + text + '~~'
 
 export const header = (id: string, title: string): string => {
   return `---
@@ -98,8 +99,10 @@ const printExample = (example: Option<string>): string =>
 
 const printSignature = (signature: string): string => CRLF + CRLF + italic('Signature') + CRLF + ts(signature)
 
+const handleDeprecated = (s: string, deprecated: boolean): string => deprecated ? strike(s) + ' (deprecated)' : s
+
 const printMethod = (m: Method): string => {
-  let s = CRLF + h3(m.name)
+  let s = CRLF + h3(handleDeprecated(m.name, m.deprecated))
   s += CRLF + italic('method')
   s += CRLF + CRLF + italic(`since ${m.since}`)
   s += CRLF + printSignature(m.signature)
@@ -109,7 +112,7 @@ const printMethod = (m: Method): string => {
 }
 
 const printData = (d: Data): string => {
-  let s = `\n${h3(d.name)}`
+  let s = CRLF + h3(d.name)
   s += CRLF + italic('data')
   s += CRLF + CRLF + italic(`since ${d.since}`)
   s += CRLF + printSignature(d.signature)
@@ -127,7 +130,7 @@ const printData = (d: Data): string => {
 }
 
 const printInstance = (i: Instance): string => {
-  let s = `\n${h3(i.name)}`
+  let s = CRLF + h3(i.name)
   s += CRLF + italic('instance')
   s += CRLF + CRLF + italic(`since ${i.since}`)
   s += CRLF + printSignature(i.signature)
@@ -136,7 +139,7 @@ const printInstance = (i: Instance): string => {
 }
 
 const printConstant = (c: Constant): string => {
-  let s = `\n${h3(c.name)}`
+  let s = CRLF + h3(c.name)
   s += CRLF + italic('constant')
   s += CRLF + CRLF + italic(`since ${c.since}`)
   s += CRLF + printSignature(c.signature)
@@ -145,7 +148,7 @@ const printConstant = (c: Constant): string => {
 }
 
 const printFunc = (f: Func): string => {
-  let s = `\n${h3(f.name)}`
+  let s = CRLF + h3(handleDeprecated(f.name, f.deprecated))
   s += CRLF + italic('function')
   s += CRLF + CRLF + italic(`since ${f.since}`)
   if (f.isAlias) {
@@ -158,7 +161,7 @@ const printFunc = (f: Func): string => {
 }
 
 const printTypeclass = (tc: Typeclass): string => {
-  let s = `\n${h3(tc.name)}`
+  let s = CRLF + h3(tc.name)
   s += CRLF + italic('type class')
   s += CRLF + printSignature(tc.signature)
   s += printDescription(tc.description)
diff --git a/docs-generator/parser.ts b/docs-generator/parser.ts
index 6b0de992..b3bd10bb 100644
--- a/docs-generator/parser.ts
+++ b/docs-generator/parser.ts
@@ -88,13 +88,15 @@ const getMethod = (md: MethodDeclaration): Method => {
   const annotation = getAnnotation(md.getDocumentationCommentNodes())
   const since = getSince(annotation)
   const example = getExample(annotation)
+  const deprecated = getDeprecated(annotation)
   return {
     type: 'method',
     name,
     signature,
     description,
     since: since.getOrElse('1.0.0'),
-    example
+    example,
+    deprecated
   }
 }
 
@@ -142,6 +144,14 @@ const getExample = (annotation: Annotation): Option<string> => {
   return fromNullable(annotation.tags.filter(isExampleTag)[0]).mapNullable(tag => tag.description)
 }
 
+const isDeprecatedTag = (tag: Tag): boolean => {
+  return tag.title === 'deprecated'
+}
+
+const getDeprecated = (annotation: Annotation): boolean => {
+  return fromNullable(annotation.tags.filter(isDeprecatedTag)[0]).isSome()
+}
+
 /** parses data types which are unions */
 const parseTypeAliasDeclarationData = (tad: TypeAliasDeclaration): ParseResult<Export> => {
   return new ReaderEither(e => {
@@ -278,10 +288,11 @@ const parseFunctionVariableDeclaration = (vd: VariableDeclaration): ParseResult<
           const signature = text.substring(start, end.getOrElse(text.length))
           const since = getSince(annotation)
           const example = getExample(annotation)
+          const deprecated = getDeprecated(annotation)
           if (since.isNone()) {
             return ko(new SinceMissing(e.currentModuleName, name))
           } else {
-            return ok(new Func(name, signature, description, isAlias(annotation), since.value, example))
+            return ok(new Func(name, signature, description, isAlias(annotation), since.value, example,deprecated))
           }
         }
       }
@@ -315,10 +326,11 @@ const parseFunctionDeclaration = (f: FunctionDeclaration): ParseResult<Export> =
       const signature = text.substring(start, end === -1 ? text.length : end)
       const since = getSince(annotation)
       const example = getExample(annotation)
+      const deprecated = getDeprecated(annotation)
       if (since.isNone()) {
         return ko(new SinceMissing(e.currentModuleName, name))
       } else {
-        return ok(new Func(name, signature, description, false, since.value, example))
+        return ok(new Func(name, signature, description, false, since.value, example, deprecated))
       }
     }
     return notFound
diff --git a/src/Array.ts b/src/Array.ts
index 0fea391a..f4988563 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -17,6 +17,7 @@ import { Unfoldable1 } from './Unfoldable'
 import { Endomorphism, Predicate, Refinement, concat, tuple } from './function'
 import { Compactable1, Separated } from './Compactable'
 import { Filterable1 } from './Filterable'
+import { Witherable1 } from './Witherable'
 
 // Adapted from https://github.com/purescript/purescript-arrays
 
@@ -833,6 +834,18 @@ export const catOptions = compact
  */
 export const mapOption = filterMap
 
+const wither = <F>(F: Applicative<F>): (<A, B>(ta: A[], f: (a: A) => HKT<F, Option<B>>) => HKT<F, B[]>) => {
+  const traverseF = traverse(F)
+  return (wa, f) => F.map(traverseF(wa, f), compact)
+}
+
+const wilt = <F>(
+  F: Applicative<F>
+): (<RL, RR, A>(wa: A[], f: (a: A) => HKT<F, Either<RL, RR>>) => HKT<F, Separated<RL[], RR[]>>) => {
+  const traverseF = traverse(F)
+  return (wa, f) => F.map(traverseF(wa, f), separate)
+}
+
 export const array: Monad1<URI> &
   Foldable1<URI> &
   Unfoldable1<URI> &
@@ -841,7 +854,8 @@ export const array: Monad1<URI> &
   Plus1<URI> &
   Extend1<URI> &
   Compactable1<URI> &
-  Filterable1<URI> = {
+  Filterable1<URI> &
+  Witherable1<URI> = {
   URI,
   map,
   compact,
@@ -858,5 +872,7 @@ export const array: Monad1<URI> &
   traverse,
   zero,
   alt,
-  extend
+  extend,
+  wither,
+  wilt
 }
diff --git a/src/Either.ts b/src/Either.ts
index b40eb16b..ca58eddb 100644
--- a/src/Either.ts
+++ b/src/Either.ts
@@ -14,6 +14,7 @@ import { Validation } from './Validation'
 import { Compactable2C, Separated } from './Compactable'
 import { Monoid } from './Monoid'
 import { Filterable2C } from './Filterable'
+import { Witherable2C } from './Witherable'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -474,7 +475,7 @@ export function getCompactable<L>(ML: Monoid<L>): Compactable2C<URI, L> {
 }
 
 /**
- * Builds {@link Filterable} instance for {@link Either} gived {@link Monoid} for the left side
+ * Builds {@link Filterable} instance for {@link Either} given {@link Monoid} for the left side
  * @function
  * @since 1.7.0
  */
@@ -541,6 +542,40 @@ export function getFilterable<L>(ML: Monoid<L>): Filterable2C<URI, L> {
   }
 }
 
+/**
+ * Builds {@link Witherable} instance for {@link Either} given {@link Monoid} for the left side
+ * @function
+ * @since 1.7.0
+ */
+export function getWitherable<L>(ML: Monoid<L>): Witherable2C<URI, L> {
+  const filterableEither = getFilterable(ML)
+
+  const wither = <F>(
+    F: Applicative<F>
+  ): (<A, B>(wa: Either<L, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Either<L, B>>) => {
+    const traverseF = traverse(F)
+    return (wa, f) => F.map(traverseF(wa, f), filterableEither.compact)
+  }
+
+  const wilt = <F>(
+    F: Applicative<F>
+  ): (<RL, RR, A>(
+    wa: Either<L, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<Either<L, RL>, Either<L, RR>>>) => {
+    const traverseF = traverse(F)
+    return (wa, f) => F.map(traverseF(wa, f), filterableEither.separate)
+  }
+
+  return {
+    ...filterableEither,
+    traverse,
+    reduce,
+    wither,
+    wilt
+  }
+}
+
 /**
  * @instance
  * @since 1.0.0
diff --git a/src/Monoid.ts b/src/Monoid.ts
index 711d31ea..ec86f422 100644
--- a/src/Monoid.ts
+++ b/src/Monoid.ts
@@ -171,13 +171,16 @@ export const getEndomorphismMonoid = <A = never>(): Monoid<Endomorphism<A>> => {
  * @function
  * @since 1.0.0
  */
-export const getRecordMonoid = <O>(Ms: { [K in keyof O]: Monoid<O[K]> }): Monoid<O> => {
+export const getRecordMonoid = <O extends { [key: string]: any }>(
+  monoids: { [K in keyof O]: Monoid<O[K]> }
+): Monoid<O> => {
   const empty: any = {}
-  for (const k in Ms) {
-    empty[k] = Ms[k].empty
+  const keys = Object.keys(monoids)
+  for (const key of keys) {
+    empty[key] = monoids[key].empty
   }
   return {
-    ...getRecordSemigroup<O>(Ms),
+    ...getRecordSemigroup<O>(monoids),
     empty
   }
 }
diff --git a/src/Option.ts b/src/Option.ts
index 56b2dd6d..3c9e7a0f 100644
--- a/src/Option.ts
+++ b/src/Option.ts
@@ -14,6 +14,7 @@ import { Traversable1 } from './Traversable'
 import { identity, Lazy, not, Predicate, Refinement, toString } from './function'
 import { Compactable1, Separated } from './Compactable'
 import { Filterable1 } from './Filterable'
+import { Witherable1 } from './Witherable'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -586,6 +587,33 @@ const partition = <A>(fa: Option<A>, p: Predicate<A>): Separated<Option<A>, Opti
   right: fa.filter(p)
 })
 
+const wither = <F>(F: Applicative<F>) => <A, B>(fa: Option<A>, f: (a: A) => HKT<F, Option<B>>): HKT<F, Option<B>> =>
+  fa.isNone() ? F.of(fa as any) : f(fa.value)
+
+const wilt = <F>(F: Applicative<F>) => <RL, RR, A>(
+  fa: Option<A>,
+  f: (a: A) => HKT<F, Either<RL, RR>>
+): HKT<F, Separated<Option<RL>, Option<RR>>> => {
+  if (fa.isNone()) {
+    return F.of({
+      left: none,
+      right: none
+    })
+  }
+  return F.map(f(fa.value), e => {
+    if (e.isLeft()) {
+      return {
+        left: some(e.value),
+        right: none
+      }
+    }
+    return {
+      left: none,
+      right: some(e.value)
+    }
+  })
+}
+
 /**
  * @instance
  * @since 1.0.0
@@ -597,7 +625,8 @@ export const option: Monad1<URI> &
   Alternative1<URI> &
   Extend1<URI> &
   Compactable1<URI> &
-  Filterable1<URI> = {
+  Filterable1<URI> &
+  Witherable1<URI> = {
   URI,
   map,
   of,
@@ -613,5 +642,7 @@ export const option: Monad1<URI> &
   filter,
   filterMap,
   partition,
-  partitionMap
+  partitionMap,
+  wither,
+  wilt
 }
diff --git a/src/Semigroup.ts b/src/Semigroup.ts
index 88f28111..2592a91d 100644
--- a/src/Semigroup.ts
+++ b/src/Semigroup.ts
@@ -70,8 +70,9 @@ export const getRecordSemigroup = <O extends { [key: string]: any }>(
   return {
     concat: (x, y) => {
       const r: any = {}
-      for (const k in semigroups) {
-        r[k] = semigroups[k].concat(x[k], y[k])
+      const keys = Object.keys(semigroups)
+      for (const key of keys) {
+        r[key] = semigroups[key].concat(x[key], y[key])
       }
       return r
     }
diff --git a/src/StrMap.ts b/src/StrMap.ts
index ad5e7d1d..cc32b948 100644
--- a/src/StrMap.ts
+++ b/src/StrMap.ts
@@ -13,6 +13,7 @@ import { Predicate, tuple } from './function'
 import { Either } from './Either'
 import { Compactable1, Separated } from './Compactable'
 import { Filterable1 } from './Filterable'
+import { Witherable1 } from './Witherable'
 
 // https://github.com/purescript/purescript-maps
 
@@ -36,10 +37,11 @@ export class StrMap<A> {
   readonly _URI!: URI
   constructor(readonly value: { [key: string]: A }) {}
   mapWithKey<B>(f: (k: string, a: A) => B): StrMap<B> {
-    const o = this.value
+    const value = this.value
     const r: { [key: string]: B } = {}
-    for (let k in o) {
-      r[k] = f(k, o[k])
+    const keys = Object.keys(value)
+    for (const key of keys) {
+      r[key] = f(key, value[key])
     }
     return new StrMap(r)
   }
@@ -119,8 +121,10 @@ export function traverseWithKey<F>(
       concatCurried(getLastSemigroup())
     )
     let out: HKT<F, StrMap<B>> = F.of(empty)
-    for (let k in ta.value) {
-      out = concatA2(out)(F.map(f(k, ta.value[k]), b => singleton(k, b)))
+    const value = ta.value
+    const keys = Object.keys(value)
+    for (const key of keys) {
+      out = concatA2(out)(F.map(f(key, value[key]), b => singleton(key, b)))
     }
     return out
   }
@@ -159,10 +163,7 @@ export const size = <A>(d: StrMap<A>): number => {
  * @since 1.0.0
  */
 export const isEmpty = <A>(d: StrMap<A>): boolean => {
-  for (const _ in d.value) {
-    return false
-  }
-  return true
+  return Object.keys(d.value).length === 0
 }
 
 /**
@@ -231,8 +232,10 @@ export function fromFoldable<F>(
  */
 export const collect = <A, B>(d: StrMap<A>, f: (k: string, a: A) => B): Array<B> => {
   const out: Array<B> = []
-  for (let k in d.value) {
-    out.push(f(k, d.value[k]))
+  const value = d.value
+  const keys = Object.keys(value)
+  for (const key of keys) {
+    out.push(f(key, d.value[key]))
   }
   return out
 }
@@ -384,11 +387,27 @@ const separate = <RL, RR>(fa: StrMap<Either<RL, RR>>): Separated<StrMap<RL>, Str
   }
 }
 
+const wither = <F>(F: Applicative<F>): (<A, B>(wa: StrMap<A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, StrMap<B>>) => {
+  const traverseF = traverse(F)
+  return (wa, f) => F.map(traverseF(wa, f), compact)
+}
+
+const wilt = <F>(
+  F: Applicative<F>
+): (<RL, RR, A>(wa: StrMap<A>, f: (a: A) => HKT<F, Either<RL, RR>>) => HKT<F, Separated<StrMap<RL>, StrMap<RR>>>) => {
+  const traverseF = traverse(F)
+  return (wa, f) => F.map(traverseF(wa, f), separate)
+}
 /**
  * @instance
  * @since 1.0.0
  */
-export const strmap: Functor1<URI> & Foldable1<URI> & Traversable1<URI> & Compactable1<URI> & Filterable1<URI> = {
+export const strmap: Functor1<URI> &
+  Foldable1<URI> &
+  Traversable1<URI> &
+  Compactable1<URI> &
+  Filterable1<URI> &
+  Witherable1<URI> = {
   URI,
   map,
   reduce,
@@ -398,5 +417,7 @@ export const strmap: Functor1<URI> & Foldable1<URI> & Traversable1<URI> & Compac
   filter,
   filterMap,
   partition,
-  partitionMap
+  partitionMap,
+  wither,
+  wilt
 }
diff --git a/src/Traversable.ts b/src/Traversable.ts
index 4031e9d0..6d8c5339 100644
--- a/src/Traversable.ts
+++ b/src/Traversable.ts
@@ -21,39 +21,216 @@ import {
   FunctorComposition11,
   getFunctorComposition
 } from './Functor'
-import { HKT, HKT2, HKT3, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
 
-/** @typeclass */
+/**
+ * Interface for {@link Traversable.traverse}
+ * @since 1.7.0
+ */
+export interface Traverse<T> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: HKT<T, A>,
+    f: (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: (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: (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: (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: (a: A) => Type<F, B>) => Type<F, HKT<T, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: HKT<T, A>, f: (a: A) => HKT<F, B>) => HKT<F, HKT<T, B>>
+}
+
+/**
+ * Interface for {@link Traversable1.traverse}
+ * @see Traverse
+ * @since 1.7.0
+ */
+export interface Traverse1<T extends URIS> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type<T, A>,
+    f: (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: (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: (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: (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: (a: A) => Type<F, B>) => Type<F, Type<T, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type<T, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type<T, B>>
+}
+
+/**
+ * Interface for {@link Traversable2.traverse}
+ * @see Traverse
+ * @since 1.7.0
+ */
+export interface Traverse2<T extends URIS2> {
+  <F extends URIS3>(F: Applicative3<F>): <TL, FU, FL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type2<T, TL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <TL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type2<T, TL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <TL, FL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type2<T, TL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <TL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type2<T, TL, B>>
+  <F extends URIS>(F: Applicative1<F>): <TL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type<F, B>
+  ) => Type<F, Type2<T, TL, B>>
+  <F>(F: Applicative<F>): <TL, A, B>(ta: Type2<T, TL, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type2<T, TL, B>>
+}
+
+/**
+ * Interface for {@link Traversable2C.traverse}
+ * @see Traverse
+ * @since 1.7.0
+ */
+export interface Traverse2C<T extends URIS2, TL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type2<T, TL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type2<T, TL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type2<T, TL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type2<T, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type2<T, TL, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(ta: Type2<T, TL, A>, f: (a: A) => Type<F, B>) => Type<F, Type2<T, TL, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type2<T, TL, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type2<T, TL, B>>
+}
+
+/**
+ * Interface for {@link Traversable3.traverse}
+ * @see Traverse
+ * @since 1.7.0
+ */
+export interface Traverse3<T extends URIS3> {
+  <F extends URIS3>(F: Applicative3<F>): <TU, TL, FU, FL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type3<T, TU, TL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <TU, TL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type3<T, TU, TL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <TU, TL, FL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type3<T, TU, TL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <TU, TL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type3<T, TU, TL, B>>
+  <F extends URIS>(F: Applicative1<F>): <TU, TL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type<F, B>
+  ) => Type<F, Type3<T, TU, TL, B>>
+  <F>(F: Applicative<F>): <TU, TL, A, B>(ta: Type3<T, TU, TL, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type3<T, TU, TL, B>>
+}
+
+/**
+ * Interface for {@link Traversable3C.traverse}
+ * @see Traverse
+ * @since 1.7.0
+ */
+export interface Traverse3C<T extends URIS3, TU, TL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type3<T, TU, TL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type3<F, FU, FL, B>
+  ) => Type3<F, FU, FL, Type3<T, TU, TL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type3<T, TU, TL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type2<F, FL, B>
+  ) => Type2<F, FL, Type3<T, TU, TL, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(
+    ta: Type3<T, TU, TL, A>,
+    f: (a: A) => Type<F, B>
+  ) => Type<F, Type3<T, TU, TL, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type3<T, TU, TL, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type3<T, TU, TL, B>>
+}
+
+/**
+ * @typeclass
+ * `Traversable` represents data structures which can be _traversed_ accumulating results and effects in some {@link Applicative} functor.
+ */
 export interface Traversable<T> extends Functor<T>, Foldable<T> {
-  readonly traverse: <F>(F: Applicative<F>) => <A, B>(ta: HKT<T, A>, f: (a: A) => HKT<F, B>) => HKT<F, HKT<T, B>>
+  /**
+   * Runs an action for every element in a data structure and accumulates the results
+   */
+  traverse: Traverse<T>
 }
 
+/**
+ * @see Traversable
+ */
 export interface Traversable1<T extends URIS> extends Functor1<T>, Foldable1<T> {
-  readonly traverse: <F>(F: Applicative<F>) => <A, B>(ta: Type<T, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type<T, B>>
+  traverse: Traverse1<T>
 }
 
+/**
+ * @see Traversable
+ */
 export interface Traversable2<T extends URIS2> extends Functor2<T>, Foldable2<T> {
-  readonly traverse: <F>(
-    F: Applicative<F>
-  ) => <L, A, B>(ta: Type2<T, L, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type2<T, L, B>>
+  traverse: Traverse2<T>
 }
 
-export interface Traversable3<T extends URIS3> extends Functor3<T>, Foldable3<T> {
-  readonly traverse: <F>(
-    F: Applicative<F>
-  ) => <U, L, A, B>(ta: Type3<T, U, L, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type3<T, U, L, B>>
+/**
+ * @see Traversable
+ */
+export interface Traversable2C<T extends URIS2, TL> extends Functor2C<T, TL>, Foldable2C<T, TL> {
+  traverse: Traverse2C<T, TL>
 }
 
-export interface Traversable2C<T extends URIS2, L> extends Functor2C<T, L>, Foldable2C<T, L> {
-  readonly traverse: <F>(
-    F: Applicative<F>
-  ) => <A, B>(ta: HKT2<T, L, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type2<T, L, B>>
+/**
+ * @see Traversable
+ */
+export interface Traversable3<T extends URIS3> extends Functor3<T>, Foldable3<T> {
+  traverse: Traverse3<T>
 }
 
-export interface Traversable3C<T extends URIS3, U, L> extends Functor3C<T, U, L>, Foldable3C<T, U, L> {
-  readonly traverse: <F>(
-    F: Applicative<F>
-  ) => <A, B>(ta: HKT3<T, U, L, A>, f: (a: A) => HKT<F, B>) => HKT<F, Type3<T, U, L, B>>
+/**
+ * @see Traversable
+ */
+export interface Traversable3C<T extends URIS3, TU, TL> extends Functor3C<T, TU, TL>, Foldable3C<T, TU, TL> {
+  traverse: Traverse3C<T, TU, TL>
 }
 
 export interface TraversableComposition<F, G> extends FoldableComposition<F, G>, FunctorComposition<F, G> {
@@ -99,6 +276,8 @@ export function traverse<F, T>(
   T: Traversable<T>
 ): <A, B>(ta: HKT<T, A>, f: (a: A) => HKT<F, B>) => HKT<F, HKT<T, B>>
 /**
+ * @deprecated
+ * Use {@link Traversable.traverse}
  * @function
  * @since 1.0.0
  */
diff --git a/src/Validation.ts b/src/Validation.ts
index efe1fffe..61dacad3 100644
--- a/src/Validation.ts
+++ b/src/Validation.ts
@@ -14,6 +14,7 @@ import { Bifunctor2 } from './Bifunctor'
 import { Compactable2C, Separated } from './Compactable'
 import { Option } from './Option'
 import { Filterable2C } from './Filterable'
+import { Witherable2C } from './Witherable'
 
 // Adapted from https://github.com/purescript/purescript-validation
 
@@ -483,6 +484,40 @@ export function getFilterable<L>(ML: Monoid<L>): Filterable2C<URI, L> {
   }
 }
 
+/**
+ * Builds {@link Witherable} instance for {@link Validation} given {@link Monoid} for the left side
+ * @function
+ * @since 1.7.0
+ */
+export function getWitherable<L>(ML: Monoid<L>): Witherable2C<URI, L> {
+  const filterableValidation = getFilterable(ML)
+
+  const wither = <F>(
+    F: Applicative<F>
+  ): (<A, B>(wa: Validation<L, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Validation<L, B>>) => {
+    const traverseF = traverse(F)
+    return (wa, f) => F.map(traverseF(wa, f), filterableValidation.compact)
+  }
+
+  const wilt = <F>(
+    F: Applicative<F>
+  ): (<RL, RR, A>(
+    wa: Validation<L, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<Validation<L, RL>, Validation<L, RR>>>) => {
+    const traverseF = traverse(F)
+    return (wa, f) => F.map(traverseF(wa, f), filterableValidation.separate)
+  }
+
+  return {
+    ...filterableValidation,
+    traverse,
+    reduce,
+    wither,
+    wilt
+  }
+}
+
 /**
  * @instance
  * @since 1.0.0
diff --git a/src/Witherable.ts b/src/Witherable.ts
new file mode 100644
index 00000000..42e37bb7
--- /dev/null
+++ b/src/Witherable.ts
@@ -0,0 +1,424 @@
+import { HKT, Type, Type2, Type3, URIS, URIS2, URIS3 } from './HKT'
+import { Option } from './Option'
+import { Traversable, Traversable1, Traversable2, Traversable2C, Traversable3, Traversable3C } from './Traversable'
+import { Applicative, Applicative1, Applicative2, Applicative2C, Applicative3, Applicative3C } from './Applicative'
+import { Filterable, Filterable1, Filterable2, Filterable2C, Filterable3, Filterable3C } from './Filterable'
+import { Either } from './Either'
+import { Separated } from './Compactable'
+
+/**
+ * Interface for {@link Witherable.wither}
+ * @since 1.7.0
+ */
+export interface Wither<W> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: HKT<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, HKT<W, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: HKT<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, HKT<W, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: HKT<W, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, HKT<W, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: HKT<W, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, HKT<W, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(ta: HKT<W, A>, f: (a: A) => Type<F, Option<B>>) => Type<F, HKT<W, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: HKT<W, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, HKT<W, B>>
+}
+
+/**
+ * @see Wither
+ * @since 1.7.0
+ */
+export interface Wither1<W extends URIS> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type<W, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type<W, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type<W, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type<W, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type<W, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type<W, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(ta: Type<W, A>, f: (a: A) => Type<F, Option<B>>) => Type<F, Type<W, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type<W, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Type<W, B>>
+}
+
+/**
+ * @see Wither
+ * @since 1.7.0
+ */
+export interface Wither2<W extends URIS2> {
+  <F extends URIS3>(F: Applicative3<F>): <WL, FU, FL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type2<W, WL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <WL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type2<W, WL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <WL, FL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type2<W, WL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <WL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type2<W, WL, B>>
+  <F extends URIS>(F: Applicative1<F>): <WL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type<F, Option<B>>
+  ) => Type<F, Type2<W, WL, B>>
+  <F>(F: Applicative<F>): <WL, A, B>(ta: Type2<W, WL, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Type2<W, WL, B>>
+}
+
+/**
+ * @see Wither
+ * @since 1.7.0
+ */
+export interface Wither2C<W extends URIS2, WL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type2<W, WL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type2<W, WL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type2<W, WL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type2<W, WL, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(
+    ta: Type2<W, WL, A>,
+    f: (a: A) => Type<F, Option<B>>
+  ) => Type<F, Type2<W, WL, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type2<W, WL, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Type2<W, WL, B>>
+}
+
+/**
+ * @see Wither
+ * @since 1.7.0
+ */
+export interface Wither3<W extends URIS3> {
+  <F extends URIS3>(F: Applicative3<F>): <WU, WL, FU, FL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type3<W, WU, WL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <WU, WL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type3<W, WU, WL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <WU, WL, FL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type3<W, WU, WL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <WU, WL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type3<W, WU, WL, B>>
+  <F extends URIS>(F: Applicative1<F>): <WU, WL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type<F, Option<B>>
+  ) => Type<F, Type3<W, WU, WL, B>>
+  <F>(F: Applicative<F>): <WU, WL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => HKT<F, Option<B>>
+  ) => HKT<F, Type3<W, WU, WL, B>>
+}
+
+/**
+ * @see Wither
+ * @since 1.7.0
+ */
+export interface Wither3C<W extends URIS3, WU, WL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type3<W, WU, WL, B>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Option<B>>
+  ) => Type3<F, FU, FL, Type3<W, WU, WL, B>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type3<W, WU, WL, B>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Option<B>>
+  ) => Type2<F, FL, Type3<W, WU, WL, B>>
+  <F extends URIS>(F: Applicative1<F>): <A, B>(
+    ta: Type3<W, WU, WL, A>,
+    f: (a: A) => Type<F, Option<B>>
+  ) => Type<F, Type3<W, WU, WL, B>>
+  <F>(F: Applicative<F>): <A, B>(ta: Type3<W, WU, WL, A>, f: (a: A) => HKT<F, Option<B>>) => HKT<F, Type3<W, WU, WL, B>>
+}
+
+/**
+ * Interface for {@link Witherable.wilt}
+ * @since 1.7.0
+ */
+export interface Wilt<W> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, HKT<W, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, HKT<W, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, HKT<W, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, HKT<W, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, HKT<W, RR>>>
+  <F>(F: Applicative<F>): <RL, RR, A>(
+    wa: HKT<W, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, HKT<W, RR>>>
+}
+
+/**
+ * @see Wilt
+ * @since 1.7.0
+ */
+export interface Wilt1<W extends URIS> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type<W, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type<W, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type<W, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type<W, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, Type<W, RR>>>
+  <F>(F: Applicative<F>): <RL, RR, A>(
+    wa: Type<W, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, Type<W, RR>>>
+}
+
+/**
+ * @see Wilt
+ * @since 1.7.0
+ */
+export interface Wilt2<W extends URIS2> {
+  <F extends URIS3>(F: Applicative3<F>): <WL, FU, FL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <WL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <WL, FL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <WL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <WL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F>(F: Applicative<F>): <WL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+}
+
+/**
+ * @see Wilt
+ * @since 1.7.0
+ */
+export interface Wilt2C<W extends URIS2, WL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+  <F>(F: Applicative<F>): <RL, RR, A>(
+    wa: Type2<W, WL, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, Type2<W, WL, RR>>>
+}
+
+/**
+ * @see Wilt
+ * @since 1.7.0
+ */
+export interface Wilt3<W extends URIS3> {
+  <F extends URIS3>(F: Applicative3<F>): <WU, WL, FU, FL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <WU, WL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <WU, WL, FL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <WU, WL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <WU, WL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F>(F: Applicative<F>): <WU, WL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+}
+
+/**
+ * @see Wilt
+ * @since 1.7.0
+ */
+export interface Wilt3C<W extends URIS3, WU, WL> {
+  <F extends URIS3>(F: Applicative3<F>): <FU, FL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS3, FU, FL>(F: Applicative3C<F, FU, FL>): <RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type3<F, FU, FL, Either<RL, RR>>
+  ) => Type3<F, FU, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS2>(F: Applicative2<F>): <FL, RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS2, FL>(F: Applicative2C<F, FL>): <RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type2<F, FL, Either<RL, RR>>
+  ) => Type2<F, FL, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F extends URIS>(F: Applicative1<F>): <RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => Type<F, Either<RL, RR>>
+  ) => Type<F, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+  <F>(F: Applicative<F>): <RL, RR, A>(
+    wa: Type3<W, WU, WL, A>,
+    f: (a: A) => HKT<F, Either<RL, RR>>
+  ) => HKT<F, Separated<HKT<W, RL>, Type3<W, WU, WL, RR>>>
+}
+
+/**
+ * @typeclass
+ * `Witherable` represents data structures which can be _partitioned_ with effects in some {@link Applicative} functor.
+ * - {@link wilt}
+ * - {@link wither}
+ *
+ * @since 1.7.0
+ * @see https://github.com/LiamGoodacre/purescript-filterable/blob/master/src/Data/Witherable.purs
+ */
+export interface Witherable<T> extends Traversable<T>, Filterable<T> {
+  /**
+   * Partition a structure with effects
+   */
+  wilt: Wilt<T>
+
+  /**
+   * Filter a structure  with effects
+   */
+  wither: Wither<T>
+}
+
+/**
+ * @since 1.7.0
+ * @see Witherable
+ */
+export interface Witherable1<T extends URIS> extends Traversable1<T>, Filterable1<T> {
+  wilt: Wilt1<T>
+  wither: Wither1<T>
+}
+
+/**
+ * @since 1.7.0
+ * @see Witherable
+ */
+export interface Witherable2<T extends URIS2> extends Traversable2<T>, Filterable2<T> {
+  wilt: Wilt2<T>
+  wither: Wither2<T>
+}
+
+/**
+ * @since 1.7.0
+ * @see Witherable
+ */
+export interface Witherable2C<T extends URIS2, TL> extends Traversable2C<T, TL>, Filterable2C<T, TL> {
+  wilt: Wilt2C<T, TL>
+  wither: Wither2C<T, TL>
+}
+
+/**
+ * @since 1.7.0
+ * @see Witherable
+ */
+export interface Witherable3<T extends URIS3> extends Traversable3<T>, Filterable3<T> {
+  wilt: Wilt3<T>
+  wither: Wither3<T>
+}
+
+/**
+ * @since 1.7.0
+ * @see Witherable
+ */
+export interface Witherable3C<T extends URIS3, TU, TL> extends Traversable3C<T, TU, TL>, Filterable3C<T, TU, TL> {
+  wilt: Wilt3C<T, TU, TL>
+  wither: Wither3C<T, TU, TL>
+}
diff --git a/src/index.ts b/src/index.ts
index 934fdfa0..bc295d7f 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -152,3 +152,5 @@ import * as compactable from './Compactable'
 export { compactable }
 import * as filterable from './Filterable'
 export { filterable }
+import * as witherable from './Witherable'
+export { witherable }
diff --git a/tslint.json b/tslint.json
index c535d309..4278f24b 100644
--- a/tslint.json
+++ b/tslint.json
@@ -6,6 +6,7 @@
     "variable-name": false,
     "quotemark": [true, "single", "jsx-double"],
     "ter-indent": false,
-    "strict-boolean-expressions": true
+    "strict-boolean-expressions": true,
+    "forin": true
   }
 }


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index 17ee9a9f..5e8d22b3 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -54,6 +54,9 @@ import { contramap as contramapOrd, ordNumber, ordString } from '../src/Ord'
 import { contramap, getArraySetoid, setoidBoolean, setoidNumber, setoidString } from '../src/Setoid'
 import { traverse } from '../src/Traversable'
 import { identity, tuple } from '../src/function'
+import { Identity, identity as I } from '../src/Identity'
+
+const p = (n: number) => n > 2
 
 describe('Array', () => {
   const as = [1, 2, 3]
@@ -450,8 +453,21 @@ describe('Array', () => {
   })
 
   it('partition', () => {
-    const p = (n: number) => n > 2
     assert.deepEqual(array.partition([], p), { left: [], right: [] })
     assert.deepEqual(array.partition([1, 3], p), { left: [1], right: [3] })
   })
+
+  it('wither', () => {
+    const witherIdentity = array.wither(I)
+    const f = (n: number) => new Identity(p(n) ? some(n + 1) : none)
+    assert.deepEqual(witherIdentity([], f), new Identity([]))
+    assert.deepEqual(witherIdentity([1, 3], f), new Identity([4]))
+  })
+
+  it('wilt', () => {
+    const wiltIdentity = array.wilt(I)
+    const f = (n: number) => new Identity(p(n) ? right(n + 1) : left(n - 1))
+    assert.deepEqual(wiltIdentity([], f), new Identity({ left: [], right: [] }))
+    assert.deepEqual(wiltIdentity([1, 3], f), new Identity({ left: [0], right: [4] }))
+  })
 })
diff --git a/test/Either.ts b/test/Either.ts
index fafe9b6f..5608c87e 100644
--- a/test/Either.ts
+++ b/test/Either.ts
@@ -15,13 +15,15 @@ import {
   isRight,
   fromRefinement,
   getCompactable,
-  getFilterable
+  getFilterable,
+  getWitherable
 } from '../src/Either'
 import { none, option, some } from '../src/Option'
 import { setoidNumber, setoidString } from '../src/Setoid'
 import { traverse } from '../src/Traversable'
 import { failure, success } from '../src/Validation'
 import { monoidString } from '../src/Monoid'
+import { Identity, identity as I } from '../src/Identity'
 
 describe('Either', () => {
   it('fold', () => {
@@ -321,4 +323,41 @@ describe('Either', () => {
       assert.deepEqual(F.filterMap(right<string, number>(3), f), right(4))
     })
   })
+
+  describe('getWitherable', () => {
+    const W = getWitherable(monoidString)
+    const p = (n: number) => n > 2
+    it('wither', () => {
+      const f = (n: number) => new Identity(p(n) ? some(n + 1) : none)
+      const witherIdentity = W.wither(I)
+      assert.deepEqual(witherIdentity(left<string, number>('foo'), f), new Identity(left('foo')))
+      assert.deepEqual(witherIdentity(right<string, number>(1), f), new Identity(left(monoidString.empty)))
+      assert.deepEqual(witherIdentity(right<string, number>(3), f), new Identity(right(4)))
+    })
+    it('wilt', () => {
+      const wiltIdentity = W.wilt(I)
+      const f = (n: number) => new Identity(p(n) ? right(n + 1) : left(n - 1))
+      assert.deepEqual(
+        wiltIdentity(left<string, number>('foo'), f),
+        new Identity({
+          left: left('foo'),
+          right: left('foo')
+        })
+      )
+      assert.deepEqual(
+        wiltIdentity(right<string, number>(1), f),
+        new Identity({
+          left: right(0),
+          right: left(monoidString.empty)
+        })
+      )
+      assert.deepEqual(
+        wiltIdentity(right<string, number>(3), f),
+        new Identity({
+          left: left(monoidString.empty),
+          right: right(4)
+        })
+      )
+    })
+  })
 })
diff --git a/test/Option.ts b/test/Option.ts
index a2e4bd23..4be115f2 100644
--- a/test/Option.ts
+++ b/test/Option.ts
@@ -24,6 +24,7 @@ import { semigroupString } from '../src/Semigroup'
 import { setoidNumber } from '../src/Setoid'
 import { traverse } from '../src/Traversable'
 import { identity } from '../src/function'
+import { Identity, identity as I } from '../src/Identity'
 
 const p = (n: number): boolean => n > 2
 
@@ -322,4 +323,20 @@ describe('Option', () => {
     assert.deepEqual(option.partitionMap(some(1), f), { left: some(0), right: none })
     assert.deepEqual(option.partitionMap(some(3), f), { left: none, right: some(4) })
   })
+
+  it('wither', () => {
+    const witherIdentity = option.wither(I)
+    const f = (n: number) => new Identity(p(n) ? some(n + 1) : none)
+    assert.deepEqual(witherIdentity(none, f), new Identity(none))
+    assert.deepEqual(witherIdentity(some(1), f), new Identity(none))
+    assert.deepEqual(witherIdentity(some(3), f), new Identity(some(4)))
+  })
+
+  it('wilt', () => {
+    const wiltIdentity = option.wilt(I)
+    const f = (n: number) => new Identity(p(n) ? right(n + 1) : left(n - 1))
+    assert.deepEqual(wiltIdentity(none, f), new Identity({ left: none, right: none }))
+    assert.deepEqual(wiltIdentity(some(1), f), new Identity({ left: some(0), right: none }))
+    assert.deepEqual(wiltIdentity(some(3), f), new Identity({ left: none, right: some(4) }))
+  })
 })
diff --git a/test/StrMap.ts b/test/StrMap.ts
index 0c862968..4eb3f6a6 100644
--- a/test/StrMap.ts
+++ b/test/StrMap.ts
@@ -21,6 +21,7 @@ import {
 import { traverse } from '../src/Traversable'
 import { semigroupSum } from '../src/Semigroup'
 import { left, right } from '../src/Either'
+import { identity as I, Identity } from '../src/Identity'
 
 const p = (n: number) => n > 2
 
@@ -169,4 +170,24 @@ describe('StrMap', () => {
       right: new StrMap({ b: 4 })
     })
   })
+
+  it('wither', () => {
+    const witherIdentity = strmap.wither(I)
+    const f = (n: number) => new Identity(p(n) ? some(n + 1) : none)
+    assert.deepEqual(witherIdentity(new StrMap<number>({}), f), new Identity(new StrMap({})))
+    assert.deepEqual(witherIdentity(new StrMap({ a: 1, b: 3 }), f), new Identity(new StrMap({ b: 4 })))
+  })
+
+  it('wilt', () => {
+    const wiltIdentity = strmap.wilt(I)
+    const f = (n: number) => new Identity(p(n) ? right(n + 1) : left(n - 1))
+    assert.deepEqual(
+      wiltIdentity(new StrMap<number>({}), f),
+      new Identity({ left: new StrMap({}), right: new StrMap({}) })
+    )
+    assert.deepEqual(
+      wiltIdentity(new StrMap({ a: 1, b: 3 }), f),
+      new Identity({ left: new StrMap({ a: 0 }), right: new StrMap({ b: 4 }) })
+    )
+  })
 })
diff --git a/test/Validation.ts b/test/Validation.ts
index 05090e68..b1e70687 100644
--- a/test/Validation.ts
+++ b/test/Validation.ts
@@ -20,9 +20,11 @@ import {
   validation,
   getMonoid,
   getCompactable,
-  getFilterable
+  getFilterable,
+  getWitherable
 } from '../src/Validation'
 import { left, right } from '../src/Either'
+import { identity as I, Identity } from '../src/Identity'
 
 const p = (n: number): boolean => n > 2
 
@@ -236,4 +238,40 @@ describe('Validation', () => {
       assert.deepEqual(F.filterMap(success<string, number>(3), f), success(4))
     })
   })
+  describe('getWitherable', () => {
+    const W = getWitherable(monoidString)
+    const p = (n: number) => n > 2
+    it('wither', () => {
+      const f = (n: number) => new Identity(p(n) ? some(n + 1) : none)
+      const witherIdentity = W.wither(I)
+      assert.deepEqual(witherIdentity(failure<string, number>('foo'), f), new Identity(failure('foo')))
+      assert.deepEqual(witherIdentity(success<string, number>(1), f), new Identity(failure(monoidString.empty)))
+      assert.deepEqual(witherIdentity(success<string, number>(3), f), new Identity(success(4)))
+    })
+    it('wilt', () => {
+      const wiltIdentity = W.wilt(I)
+      const f = (n: number) => new Identity(p(n) ? right(n + 1) : left(n - 1))
+      assert.deepEqual(
+        wiltIdentity(failure<string, number>('foo'), f),
+        new Identity({
+          left: failure('foo'),
+          right: failure('foo')
+        })
+      )
+      assert.deepEqual(
+        wiltIdentity(success<string, number>(1), f),
+        new Identity({
+          left: success(0),
+          right: failure(monoidString.empty)
+        })
+      )
+      assert.deepEqual(
+        wiltIdentity(success<string, number>(3), f),
+        new Identity({
+          left: failure(monoidString.empty),
+          right: success(4)
+        })
+      )
+    })
+  })
 })