Repository: gcanti/fp-ts
Pull request #830 (2019-04-15 08:43:50)

New Feature: add Show type class

grossbart: To resolve the issue from #408, would it make sense to log something like "Please use the Show typeclass to convert this type to a string" instead of just letting the `inspect` call happen? Maybe remove `inspect` completely (for v2)?
gcanti: > Maybe remove inspect completely (for v2)?

Yes, that's my intention, `inspect` and `toString` will be removed

Patch:
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index 1fb2a418..6cd569fe 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -43,6 +43,7 @@ Adapted from https://github.com/purescript/purescript-arrays
 - [getMonoid (function)](#getmonoid-function)
 - [getOrd (function)](#getord-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [head (function)](#head-function)
 - [~~index~~ (function)](#index-function)
 - [init (function)](#init-function)
@@ -735,6 +736,16 @@ assert.strictEqual(O.equals(['a'], []), false)
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(S: Show<A>): Show<Array<A>> => ...
+```
+
+Added in v1.17.0
+
 # head (function)
 
 Get the first element in an array, or `None` if the array is empty
diff --git a/docs/modules/Const.ts.md b/docs/modules/Const.ts.md
index 868e8c58..d1e12164 100644
--- a/docs/modules/Const.ts.md
+++ b/docs/modules/Const.ts.md
@@ -20,6 +20,7 @@ parent: Modules
 - [getApplicative (function)](#getapplicative-function)
 - [getApply (function)](#getapply-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 
 ---
 
@@ -131,3 +132,13 @@ export const getSetoid = <L, A>(S: Setoid<L>): Setoid<Const<L, A>> => ...
 ```
 
 Added in v1.0.0
+
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(S: Show<L>): Show<Const<L, A>> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/Either.ts.md b/docs/modules/Either.ts.md
index ad7408e0..ae2a2bea 100644
--- a/docs/modules/Either.ts.md
+++ b/docs/modules/Either.ts.md
@@ -97,6 +97,7 @@ left(23).map(double) // left(23)
 - [getFilterable (function)](#getfilterable-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [getWitherable (function)](#getwitherable-function)
 - [isLeft (function)](#isleft-function)
 - [isRight (function)](#isright-function)
@@ -767,6 +768,16 @@ export const getSetoid = <L, A>(SL: Setoid<L>, SA: Setoid<A>): Setoid<Either<L,
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Either<L, A>> => ...
+```
+
+Added in v1.17.0
+
 # getWitherable (function)
 
 Builds `Witherable` instance for `Either` given `Monoid` for the left side
diff --git a/docs/modules/Identity.ts.md b/docs/modules/Identity.ts.md
index 18eee124..6d8cbc00 100644
--- a/docs/modules/Identity.ts.md
+++ b/docs/modules/Identity.ts.md
@@ -25,6 +25,7 @@ parent: Modules
 - [URI (constant)](#uri-constant)
 - [identity (constant)](#identity-constant)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 
 ---
 
@@ -188,7 +189,17 @@ Added in v1.0.0
 **Signature**
 
 ```ts
-export const getSetoid = <A>(setoid: Setoid<A>): Setoid<Identity<A>> => ...
+export const getSetoid = <A>(S: Setoid<A>): Setoid<Identity<A>> => ...
 ```
 
 Added in v1.0.0
+
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<Identity<A>> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/Map.ts.md b/docs/modules/Map.ts.md
index cf581e06..fe5345fa 100644
--- a/docs/modules/Map.ts.md
+++ b/docs/modules/Map.ts.md
@@ -18,6 +18,7 @@ parent: Modules
 - [getFilterableWithIndex (function)](#getfilterablewithindex-function)
 - [getMonoid (function)](#getmonoid-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [getTraversableWithIndex (function)](#gettraversablewithindex-function)
 - [getWitherable (function)](#getwitherable-function)
 - [insert (function)](#insert-function)
@@ -155,6 +156,16 @@ export const getSetoid = <K, A>(SK: Setoid<K>, SA: Setoid<A>): Setoid<Map<K, A>>
 
 Added in v1.14.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <K, A>(SK: Show<K>, SA: Show<A>): Show<Map<K, A>> => ...
+```
+
+Added in v1.17.0
+
 # getTraversableWithIndex (function)
 
 **Signature**
diff --git a/docs/modules/NonEmptyArray2v.ts.md b/docs/modules/NonEmptyArray2v.ts.md
index 88565701..fb4d1fed 100644
--- a/docs/modules/NonEmptyArray2v.ts.md
+++ b/docs/modules/NonEmptyArray2v.ts.md
@@ -18,6 +18,7 @@ Data structure which represents non-empty arrays
 - [cons (constant)](#cons-constant)
 - [nonEmptyArray (constant)](#nonemptyarray-constant)
 - [snoc (constant)](#snoc-constant)
+- [copy (function)](#copy-function)
 - [filter (function)](#filter-function)
 - [filterWithIndex (function)](#filterwithindex-function)
 - [findFirst (function)](#findfirst-function)
@@ -28,6 +29,7 @@ Data structure which represents non-empty arrays
 - [fromNonEmptyArray (function)](#fromnonemptyarray-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [group (function)](#group-function)
 - [groupBy (function)](#groupby-function)
 - [groupSort (function)](#groupsort-function)
@@ -37,6 +39,7 @@ Data structure which represents non-empty arrays
 - [make (function)](#make-function)
 - [max (function)](#max-function)
 - [min (function)](#min-function)
+- [modifyAt (function)](#modifyat-function)
 - [sort (function)](#sort-function)
 - [tail (function)](#tail-function)
 - [updateAt (function)](#updateat-function)
@@ -128,6 +131,16 @@ assert.deepStrictEqual(snoc([1, 2, 3], 4), [1, 2, 3, 4])
 
 Added in v1.16.0
 
+# copy (function)
+
+**Signature**
+
+```ts
+export const copy = <A>(nea: NonEmptyArray<A>): NonEmptyArray<A> => ...
+```
+
+Added in v1.17.0
+
 # filter (function)
 
 **Signature**
@@ -251,6 +264,16 @@ assert.strictEqual(S.equals(make(1, [2]), fromNonEmptyArray([1, 3])), false)
 
 Added in v1.15.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<NonEmptyArray<A>> => ...
+```
+
+Added in v1.17.0
+
 # group (function)
 
 Group equal, consecutive elements of an array into non empty arrays.
@@ -377,6 +400,16 @@ export function min<A>(ord: Ord<A>): (nea: NonEmptyArray<A>) => A { ... }
 
 Added in v1.15.0
 
+# modifyAt (function)
+
+**Signature**
+
+```ts
+export function modifyAt<A>(nea: NonEmptyArray<A>, i: number, f: (a: A) => A): Option<NonEmptyArray<A>> { ... }
+```
+
+Added in v1.17.0
+
 # sort (function)
 
 **Signature**
diff --git a/docs/modules/Option.ts.md b/docs/modules/Option.ts.md
index 3fa9a747..e161d6c9 100644
--- a/docs/modules/Option.ts.md
+++ b/docs/modules/Option.ts.md
@@ -156,6 +156,7 @@ sumLifted(some(1), none) // none
 - [getOrd (function)](#getord-function)
 - [getRefinement (function)](#getrefinement-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [isNone (function)](#isnone-function)
 - [isSome (function)](#issome-function)
 - [some (function)](#some-function)
@@ -1049,6 +1050,16 @@ assert.strictEqual(S.equals(some(1), some(1)), true)
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<Option<A>> => ...
+```
+
+Added in v1.17.0
+
 # isNone (function)
 
 Returns `true` if the option is `None`, `false` otherwise
diff --git a/docs/modules/Pair.ts.md b/docs/modules/Pair.ts.md
index e8510e45..caaa62b7 100644
--- a/docs/modules/Pair.ts.md
+++ b/docs/modules/Pair.ts.md
@@ -29,6 +29,7 @@ Adapted from https://github.com/parsonsmatt/purescript-pair
 - [getOrd (function)](#getord-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 
 ---
 
@@ -190,3 +191,13 @@ export const getSetoid = <A>(S: Setoid<A>): Setoid<Pair<A>> => ...
 ```
 
 Added in v1.0.0
+
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(S: Show<A>): Show<Pair<A>> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/Record.ts.md b/docs/modules/Record.ts.md
index d59a12b7..1b820490 100644
--- a/docs/modules/Record.ts.md
+++ b/docs/modules/Record.ts.md
@@ -28,6 +28,7 @@ parent: Modules
 - [fromFoldableMap (function)](#fromfoldablemap-function)
 - [getMonoid (function)](#getmonoid-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [insert (function)](#insert-function)
 - [isEmpty (function)](#isempty-function)
 - [isSubrecord (function)](#issubrecord-function)
@@ -357,6 +358,16 @@ export function getSetoid<A>(S: Setoid<A>): Setoid<Record<string, A>> { ... }
 
 Added in v1.10.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<Record<string, A>> => ...
+```
+
+Added in v1.17.0
+
 # insert (function)
 
 Insert or replace a key/value pair in a map
diff --git a/docs/modules/Set.ts.md b/docs/modules/Set.ts.md
index 0329c7c4..c59f9451 100644
--- a/docs/modules/Set.ts.md
+++ b/docs/modules/Set.ts.md
@@ -21,6 +21,7 @@ parent: Modules
 - [fromArray (function)](#fromarray-function)
 - [getIntersectionSemigroup (function)](#getintersectionsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [getUnionMonoid (function)](#getunionmonoid-function)
 - [insert (function)](#insert-function)
 - [intersection (function)](#intersection-function)
@@ -187,6 +188,16 @@ export const getSetoid = <A>(S: Setoid<A>): Setoid<Set<A>> => ...
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(SA: Show<A>): Show<Set<A>> => ...
+```
+
+Added in v1.17.0
+
 # getUnionMonoid (function)
 
 **Signature**
diff --git a/docs/modules/Show.ts.md b/docs/modules/Show.ts.md
new file mode 100644
index 00000000..68a7329f
--- /dev/null
+++ b/docs/modules/Show.ts.md
@@ -0,0 +1,87 @@
+---
+title: Show.ts
+nav_order: 81
+parent: Modules
+---
+
+---
+
+<h2 class="text-delta">Table of contents</h2>
+
+- [Show (interface)](#show-interface)
+- [showBoolean (constant)](#showboolean-constant)
+- [showNumber (constant)](#shownumber-constant)
+- [showString (constant)](#showstring-constant)
+- [getStructShow (function)](#getstructshow-function)
+- [getTupleShow (function)](#gettupleshow-function)
+
+---
+
+# Show (interface)
+
+The `Show` type class represents those types which can be converted into
+a human-readable `string` representation.
+
+While not required, it is recommended that for any expression `x`, the
+string `show x` be executable TypeScript code which evaluates to the same
+value as the expression `x`.
+
+**Signature**
+
+```ts
+export interface Show<A> {
+  show: (a: A) => string
+}
+```
+
+# showBoolean (constant)
+
+**Signature**
+
+```ts
+export const showBoolean: Show<boolean> = ...
+```
+
+Added in v1.17.0
+
+# showNumber (constant)
+
+**Signature**
+
+```ts
+export const showNumber: Show<number> = ...
+```
+
+Added in v1.17.0
+
+# showString (constant)
+
+**Signature**
+
+```ts
+export const showString: Show<string> = ...
+```
+
+Added in v1.17.0
+
+# getStructShow (function)
+
+**Signature**
+
+```ts
+export const getStructShow = <O extends { [key: string]: any }>(shows: { [K in keyof O]: Show<O[K]> }): Show<O> => ...
+```
+
+Added in v1.17.0
+
+# getTupleShow (function)
+
+**Signature**
+
+```ts
+export const getTupleShow = <T extends Array<Show<any>>>(
+  ...shows: T
+): Show<{ [K in keyof T]: T[K] extends Show<infer A> ? A : never }> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/State.ts.md b/docs/modules/State.ts.md
index 3634aec4..959b5ea6 100644
--- a/docs/modules/State.ts.md
+++ b/docs/modules/State.ts.md
@@ -1,6 +1,6 @@
 ---
 title: State.ts
-nav_order: 81
+nav_order: 82
 parent: Modules
 ---
 
diff --git a/docs/modules/StateT.ts.md b/docs/modules/StateT.ts.md
index 60b5fccb..f1719b4a 100644
--- a/docs/modules/StateT.ts.md
+++ b/docs/modules/StateT.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StateT.ts
-nav_order: 82
+nav_order: 83
 parent: Modules
 ---
 
diff --git a/docs/modules/Store.ts.md b/docs/modules/Store.ts.md
index 038fa6a6..5a2ed1ba 100644
--- a/docs/modules/Store.ts.md
+++ b/docs/modules/Store.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Store.ts
-nav_order: 83
+nav_order: 84
 parent: Modules
 ---
 
diff --git a/docs/modules/StrMap.ts.md b/docs/modules/StrMap.ts.md
index cadb2796..75b1bd2f 100644
--- a/docs/modules/StrMap.ts.md
+++ b/docs/modules/StrMap.ts.md
@@ -1,6 +1,6 @@
 ---
 title: StrMap.ts
-nav_order: 84
+nav_order: 85
 parent: Modules
 ---
 
@@ -42,6 +42,7 @@ Adapted from https://github.com/purescript/purescript-maps
 - [fromFoldable (function)](#fromfoldable-function)
 - [getMonoid (function)](#getmonoid-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [insert (function)](#insert-function)
 - [isEmpty (function)](#isempty-function)
 - [isSubdictionary (function)](#issubdictionary-function)
@@ -379,6 +380,16 @@ export const getSetoid = <A>(S: Setoid<A>): Setoid<StrMap<A>> => ...
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<StrMap<A>> => ...
+```
+
+Added in v1.17.0
+
 # insert (function)
 
 Insert or replace a key/value pair in a map
diff --git a/docs/modules/Strong.ts.md b/docs/modules/Strong.ts.md
index d3bd7b61..442f2d79 100644
--- a/docs/modules/Strong.ts.md
+++ b/docs/modules/Strong.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Strong.ts
-nav_order: 85
+nav_order: 86
 parent: Modules
 ---
 
diff --git a/docs/modules/Task.ts.md b/docs/modules/Task.ts.md
index 0e2a7b56..2fc3fb0a 100644
--- a/docs/modules/Task.ts.md
+++ b/docs/modules/Task.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Task.ts
-nav_order: 86
+nav_order: 87
 parent: Modules
 ---
 
diff --git a/docs/modules/TaskEither.ts.md b/docs/modules/TaskEither.ts.md
index f59027e3..47de9d13 100644
--- a/docs/modules/TaskEither.ts.md
+++ b/docs/modules/TaskEither.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TaskEither.ts
-nav_order: 87
+nav_order: 88
 parent: Modules
 ---
 
diff --git a/docs/modules/These.ts.md b/docs/modules/These.ts.md
index e6fce664..128e6843 100644
--- a/docs/modules/These.ts.md
+++ b/docs/modules/These.ts.md
@@ -1,6 +1,6 @@
 ---
 title: These.ts
-nav_order: 88
+nav_order: 89
 parent: Modules
 ---
 
@@ -69,6 +69,7 @@ Adapted from https://github.com/purescript-contrib/purescript-these
 - [getMonad (function)](#getmonad-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [isBoth (function)](#isboth-function)
 - [isThat (function)](#isthat-function)
 - [isThis (function)](#isthis-function)
@@ -481,6 +482,16 @@ export const getSetoid = <L, A>(SL: Setoid<L>, SA: Setoid<A>): Setoid<These<L, A
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<These<L, A>> => ...
+```
+
+Added in v1.17.0
+
 # isBoth (function)
 
 Returns `true` if the these is an instance of `Both`, `false` otherwise
diff --git a/docs/modules/Trace.ts.md b/docs/modules/Trace.ts.md
index b64cd23a..ed6cfc31 100644
--- a/docs/modules/Trace.ts.md
+++ b/docs/modules/Trace.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Trace.ts
-nav_order: 89
+nav_order: 90
 parent: Modules
 ---
 
diff --git a/docs/modules/Traced.ts.md b/docs/modules/Traced.ts.md
index 614096f2..7beb2f69 100644
--- a/docs/modules/Traced.ts.md
+++ b/docs/modules/Traced.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traced.ts
-nav_order: 90
+nav_order: 91
 parent: Modules
 ---
 
diff --git a/docs/modules/Traversable.ts.md b/docs/modules/Traversable.ts.md
index f5f2b78e..248d1df4 100644
--- a/docs/modules/Traversable.ts.md
+++ b/docs/modules/Traversable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traversable.ts
-nav_order: 91
+nav_order: 92
 parent: Modules
 ---
 
diff --git a/docs/modules/Traversable2v.ts.md b/docs/modules/Traversable2v.ts.md
index 8019f156..be90f785 100644
--- a/docs/modules/Traversable2v.ts.md
+++ b/docs/modules/Traversable2v.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Traversable2v.ts
-nav_order: 92
+nav_order: 93
 parent: Modules
 ---
 
diff --git a/docs/modules/TraversableWithIndex.ts.md b/docs/modules/TraversableWithIndex.ts.md
index cc975892..f8c5f97d 100644
--- a/docs/modules/TraversableWithIndex.ts.md
+++ b/docs/modules/TraversableWithIndex.ts.md
@@ -1,6 +1,6 @@
 ---
 title: TraversableWithIndex.ts
-nav_order: 93
+nav_order: 94
 parent: Modules
 ---
 
diff --git a/docs/modules/Tree.ts.md b/docs/modules/Tree.ts.md
index 63a835c6..dcc09417 100644
--- a/docs/modules/Tree.ts.md
+++ b/docs/modules/Tree.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tree.ts
-nav_order: 94
+nav_order: 95
 parent: Modules
 ---
 
@@ -34,6 +34,7 @@ type Forest<A> = Array<Tree<A>>
 - [drawTree (function)](#drawtree-function)
 - [elem (function)](#elem-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [unfoldForest (function)](#unfoldforest-function)
 - [unfoldForestM (function)](#unfoldforestm-function)
 - [unfoldTree (function)](#unfoldtree-function)
@@ -226,6 +227,16 @@ export const getSetoid = <A>(S: Setoid<A>): Setoid<Tree<A>> => ...
 
 Added in v1.6.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<Tree<A>> => ...
+```
+
+Added in v1.17.0
+
 # unfoldForest (function)
 
 Build a tree from a seed value
diff --git a/docs/modules/Tuple.ts.md b/docs/modules/Tuple.ts.md
index e3b9149b..05a502ab 100644
--- a/docs/modules/Tuple.ts.md
+++ b/docs/modules/Tuple.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Tuple.ts
-nav_order: 95
+nav_order: 96
 parent: Modules
 ---
 
@@ -35,6 +35,7 @@ Adapted from https://github.com/purescript/purescript-tuples
 - [getOrd (function)](#getord-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 
 ---
 
@@ -251,3 +252,13 @@ export const getSetoid = <L, A>(SA: Setoid<L>, SB: Setoid<A>): Setoid<Tuple<L, A
 ```
 
 Added in v1.0.0
+
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Tuple<L, A>> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/Unfoldable.ts.md b/docs/modules/Unfoldable.ts.md
index 378daf32..4b92914e 100644
--- a/docs/modules/Unfoldable.ts.md
+++ b/docs/modules/Unfoldable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Unfoldable.ts
-nav_order: 96
+nav_order: 97
 parent: Modules
 ---
 
diff --git a/docs/modules/Validation.ts.md b/docs/modules/Validation.ts.md
index 555eb030..df77d9f7 100644
--- a/docs/modules/Validation.ts.md
+++ b/docs/modules/Validation.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Validation.ts
-nav_order: 97
+nav_order: 98
 parent: Modules
 ---
 
@@ -58,6 +58,7 @@ Adapted from https://github.com/purescript/purescript-validation
 - [getMonoid (function)](#getmonoid-function)
 - [getSemigroup (function)](#getsemigroup-function)
 - [getSetoid (function)](#getsetoid-function)
+- [getShow (function)](#getshow-function)
 - [getWitherable (function)](#getwitherable-function)
 - [isFailure (function)](#isfailure-function)
 - [isSuccess (function)](#issuccess-function)
@@ -524,6 +525,16 @@ export const getSetoid = <L, A>(SL: Setoid<L>, SA: Setoid<A>): Setoid<Validation
 
 Added in v1.0.0
 
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Validation<L, A>> => ...
+```
+
+Added in v1.17.0
+
 # getWitherable (function)
 
 Builds `Witherable` instance for `Validation` given `Monoid` for the left side
diff --git a/docs/modules/Witherable.ts.md b/docs/modules/Witherable.ts.md
index bbca0272..f03bc0eb 100644
--- a/docs/modules/Witherable.ts.md
+++ b/docs/modules/Witherable.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Witherable.ts
-nav_order: 98
+nav_order: 99
 parent: Modules
 ---
 
diff --git a/docs/modules/Writer.ts.md b/docs/modules/Writer.ts.md
index 602287c3..8b2710ed 100644
--- a/docs/modules/Writer.ts.md
+++ b/docs/modules/Writer.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Writer.ts
-nav_order: 99
+nav_order: 100
 parent: Modules
 ---
 
diff --git a/docs/modules/Zipper.ts.md b/docs/modules/Zipper.ts.md
index 55ac0974..b0824e74 100644
--- a/docs/modules/Zipper.ts.md
+++ b/docs/modules/Zipper.ts.md
@@ -1,6 +1,6 @@
 ---
 title: Zipper.ts
-nav_order: 100
+nav_order: 101
 parent: Modules
 ---
 
@@ -48,6 +48,7 @@ Adapted from
 - [fromNonEmptyArray2v (function)](#fromnonemptyarray2v-function)
 - [getMonoid (function)](#getmonoid-function)
 - [getSemigroup (function)](#getsemigroup-function)
+- [getShow (function)](#getshow-function)
 
 ---
 
@@ -335,3 +336,13 @@ export const getSemigroup = <A>(S: Semigroup<A>): Semigroup<Zipper<A>> => ...
 ```
 
 Added in v1.9.0
+
+# getShow (function)
+
+**Signature**
+
+```ts
+export const getShow = <A>(S: Show<A>): Show<Zipper<A>> => ...
+```
+
+Added in v1.17.0
diff --git a/docs/modules/index.ts.md b/docs/modules/index.ts.md
index bbb49e76..f1d67955 100644
--- a/docs/modules/index.ts.md
+++ b/docs/modules/index.ts.md
@@ -87,6 +87,7 @@ parent: Modules
 - [semiring (export)](#semiring-export)
 - [set (export)](#set-export)
 - [setoid (export)](#setoid-export)
+- [show (export)](#show-export)
 - [state (export)](#state-export)
 - [stateT (export)](#statet-export)
 - [store (export)](#store-export)
@@ -742,6 +743,14 @@ export { set }
 export { setoid }
 ```
 
+# show (export)
+
+**Signature**
+
+```ts
+export { show }
+```
+
 # state (export)
 
 **Signature**
diff --git a/src/Array.ts b/src/Array.ts
index 187b647b..12044a60 100644
--- a/src/Array.ts
+++ b/src/Array.ts
@@ -22,6 +22,7 @@ import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable1 } from './Unfoldable'
 import { Witherable1 } from './Witherable'
 import { NonEmptyArray } from './NonEmptyArray2v'
+import { Show } from './Show'
 
 declare global {
   interface Array<T> {
@@ -42,6 +43,15 @@ export const URI = 'Array'
 
 export type URI = typeof URI
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(S: Show<A>): Show<Array<A>> => {
+  return {
+    show: arr => `[${arr.map(S.show).join(', ')}]`
+  }
+}
+
 /**
  *
  * @example
diff --git a/src/Const.ts b/src/Const.ts
index 5f2dc459..51df78fc 100644
--- a/src/Const.ts
+++ b/src/Const.ts
@@ -6,6 +6,7 @@ import { Monoid } from './Monoid'
 import { Semigroup } from './Semigroup'
 import { Setoid, fromEquals } from './Setoid'
 import { phantom, toString } from './function'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -44,6 +45,15 @@ export class Const<L, A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(S: Show<L>): Show<Const<L, A>> => {
+  return {
+    show: c => `new Const(${S.show(c.value)})`
+  }
+}
+
 /**
  * @since 1.0.0
  */
diff --git a/src/Either.ts b/src/Either.ts
index cdfda50f..35bcb84a 100644
--- a/src/Either.ts
+++ b/src/Either.ts
@@ -44,6 +44,7 @@ import { Traversable2v2 } from './Traversable2v'
 import { Validation } from './Validation'
 import { Witherable2C } from './Witherable'
 import { MonadThrow2 } from './MonadThrow'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -274,6 +275,15 @@ export class Right<L, A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Either<L, A>> => {
+  return {
+    show: e => e.fold(l => `left(${SL.show(l)})`, a => `right(${SA.show(a)})`)
+  }
+}
+
 /**
  * @since 1.0.0
  */
diff --git a/src/Identity.ts b/src/Identity.ts
index 26d5fe79..b8973eae 100644
--- a/src/Identity.ts
+++ b/src/Identity.ts
@@ -10,6 +10,7 @@ import { Monad1 } from './Monad'
 import { Monoid } from './Monoid'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v1 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -81,11 +82,20 @@ export class Identity<A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<Identity<A>> => {
+  return {
+    show: i => `new Identity(${S.show(i.value)})`
+  }
+}
+
 /**
  * @since 1.0.0
  */
-export const getSetoid = <A>(setoid: Setoid<A>): Setoid<Identity<A>> => {
-  return fromEquals((x, y) => setoid.equals(x.value, y.value))
+export const getSetoid = <A>(S: Setoid<A>): Setoid<Identity<A>> => {
+  return fromEquals((x, y) => S.equals(x.value, y.value))
 }
 
 const map = <A, B>(fa: Identity<A>, f: (a: A) => B): Identity<B> => {
diff --git a/src/Map.ts b/src/Map.ts
index d557cacd..2134ded9 100644
--- a/src/Map.ts
+++ b/src/Map.ts
@@ -18,6 +18,7 @@ import { FunctorWithIndex2C } from './FunctorWithIndex'
 import { Functor2 } from './Functor'
 import { Traversable2v2C } from './Traversable2v'
 import { Filterable2 } from './Filterable'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -29,6 +30,24 @@ export const URI = 'Map'
 
 export type URI = typeof URI
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <K, A>(SK: Show<K>, SA: Show<A>): Show<Map<K, A>> => {
+  return {
+    show: m => {
+      let elements = ''
+      m.forEach((a, k) => {
+        elements += `[${SK.show(k)}, ${SA.show(a)}], `
+      })
+      if (elements !== '') {
+        elements = elements.substring(0, elements.length - 2)
+      }
+      return `new Map([${elements}])`
+    }
+  }
+}
+
 /**
  * Calculate the number of key/value pairs in a map
  *
diff --git a/src/NonEmptyArray2v.ts b/src/NonEmptyArray2v.ts
index 43061536..cfb76dcd 100644
--- a/src/NonEmptyArray2v.ts
+++ b/src/NonEmptyArray2v.ts
@@ -14,6 +14,7 @@ import { Setoid } from './Setoid'
 import { compose, Predicate, Refinement } from './function'
 import { Traverse1 } from './Traversable'
 import { Sequence1 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -35,6 +36,16 @@ export interface NonEmptyArray<A> extends Array<A> {
   reverse: () => NonEmptyArray<A>
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<NonEmptyArray<A>> => {
+  const SA = A.getShow(S)
+  return {
+    show: arr => `make(${S.show(arr[0])}, ${SA.show(arr.slice(1))})`
+  }
+}
+
 /**
  * @since 1.15.0
  */
diff --git a/src/Option.ts b/src/Option.ts
index 30686820..b8f4b039 100644
--- a/src/Option.ts
+++ b/src/Option.ts
@@ -98,6 +98,7 @@ import { Semigroup } from './Semigroup'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v1 } from './Traversable2v'
 import { Witherable1 } from './Witherable'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -407,7 +408,15 @@ export class Some<A> {
 }
 
 /**
- *
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<Option<A>> => {
+  return {
+    show: oa => oa.fold('none', a => `some(${S.show(a)})`)
+  }
+}
+
+/**
  * @example
  * import { none, some, getSetoid } from 'fp-ts/lib/Option'
  * import { setoidNumber } from 'fp-ts/lib/Setoid'
diff --git a/src/Pair.ts b/src/Pair.ts
index 34aa7eaf..e4066eaa 100644
--- a/src/Pair.ts
+++ b/src/Pair.ts
@@ -12,6 +12,7 @@ import { semigroupOrdering } from './Ordering'
 import { Semigroup } from './Semigroup'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v1 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -67,6 +68,15 @@ export class Pair<A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(S: Show<A>): Show<Pair<A>> => {
+  return {
+    show: p => `new Pair(${S.show(p.fst)}, ${S.show(p.snd)})`
+  }
+}
+
 const map = <A, B>(fa: Pair<A>, f: (a: A) => B): Pair<B> => {
   return fa.map(f)
 }
diff --git a/src/Record.ts b/src/Record.ts
index ecf87a16..0c4949ae 100644
--- a/src/Record.ts
+++ b/src/Record.ts
@@ -10,6 +10,19 @@ import { none, Option, some as optionSome } from './Option'
 import { Semigroup } from './Semigroup'
 import { fromEquals, Setoid } from './Setoid'
 import { Unfoldable, Unfoldable1 } from './Unfoldable'
+import { Show, showString } from './Show'
+
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<Record<string, A>> => {
+  return {
+    show: r => {
+      const elements = collect(r, (k, a) => `${showString.show(k)}: ${S.show(a)}`).join(', ')
+      return elements === '' ? '{}' : `{ ${elements} }`
+    }
+  }
+}
 
 /**
  * Calculate the number of key/value pairs in a record
diff --git a/src/Set.ts b/src/Set.ts
index 282b1228..00c944f4 100644
--- a/src/Set.ts
+++ b/src/Set.ts
@@ -6,6 +6,25 @@ import { Setoid, fromEquals } from './Setoid'
 import { Predicate, not, Refinement, identity } from './function'
 import { Separated } from './Compactable'
 import { Option } from './Option'
+import { Show } from './Show'
+
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(SA: Show<A>): Show<Set<A>> => {
+  return {
+    show: s => {
+      let elements = ''
+      s.forEach(a => {
+        elements += SA.show(a) + ', '
+      })
+      if (elements !== '') {
+        elements = elements.substring(0, elements.length - 2)
+      }
+      return `new Set([${elements}])`
+    }
+  }
+}
 
 /**
  * @since 1.14.0
diff --git a/src/Show.ts b/src/Show.ts
new file mode 100644
index 00000000..f56d4fd7
--- /dev/null
+++ b/src/Show.ts
@@ -0,0 +1,55 @@
+/**
+ * The `Show` type class represents those types which can be converted into
+ * a human-readable `string` representation.
+ *
+ * While not required, it is recommended that for any expression `x`, the
+ * string `show x` be executable TypeScript code which evaluates to the same
+ * value as the expression `x`.
+ */
+export interface Show<A> {
+  show: (a: A) => string
+}
+
+/**
+ * @since 1.17.0
+ */
+export const showString: Show<string> = {
+  show: a => JSON.stringify(a)
+}
+
+/**
+ * @since 1.17.0
+ */
+export const showNumber: Show<number> = {
+  show: a => JSON.stringify(a)
+}
+
+/**
+ * @since 1.17.0
+ */
+export const showBoolean: Show<boolean> = {
+  show: a => JSON.stringify(a)
+}
+
+/**
+ * @since 1.17.0
+ */
+export const getStructShow = <O extends { [key: string]: any }>(shows: { [K in keyof O]: Show<O[K]> }): Show<O> => {
+  return {
+    show: s =>
+      `{ ${Object.keys(shows)
+        .map(k => `${k}: ${shows[k].show(s[k])}`)
+        .join(', ')} }`
+  }
+}
+
+/**
+ * @since 1.17.0
+ */
+export const getTupleShow = <T extends Array<Show<any>>>(
+  ...shows: T
+): Show<{ [K in keyof T]: T[K] extends Show<infer A> ? A : never }> => {
+  return {
+    show: t => `[${t.map((a, i) => shows[i].show(a)).join(', ')}]`
+  }
+}
diff --git a/src/StrMap.ts b/src/StrMap.ts
index 2233ef14..7e57755e 100644
--- a/src/StrMap.ts
+++ b/src/StrMap.ts
@@ -19,6 +19,7 @@ import { Setoid, fromEquals } from './Setoid'
 import { TraversableWithIndex1 } from './TraversableWithIndex'
 import { Unfoldable, Unfoldable1 } from './Unfoldable'
 import { Witherable1 } from './Witherable'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -178,6 +179,16 @@ export class StrMap<A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<StrMap<A>> => {
+  const SR = R.getShow(S)
+  return {
+    show: s => `new StrMap(${SR.show(s.value)})`
+  }
+}
+
 /**
  *
  * @since 1.10.0
diff --git a/src/These.ts b/src/These.ts
index 28682de0..69b40113 100644
--- a/src/These.ts
+++ b/src/These.ts
@@ -30,6 +30,7 @@ import { none, Option, some } from './Option'
 import { Semigroup } from './Semigroup'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v2 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -155,6 +156,16 @@ export class Both<L, A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<These<L, A>> => {
+  return {
+    show: t =>
+      t.fold(l => `this_(${SL.show(l)})`, a => `that(${SA.show(a)})`, (l, a) => `both(${SL.show(l)}, ${SA.show(a)})`)
+  }
+}
+
 /**
  * @since 1.0.0
  */
diff --git a/src/Tree.ts b/src/Tree.ts
index 73970962..6f79ca1a 100644
--- a/src/Tree.ts
+++ b/src/Tree.ts
@@ -15,6 +15,7 @@ import { Monad, Monad1, Monad2, Monad2C, Monad3, Monad3C } from './Monad'
 import { Monoid } from './Monoid'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v1 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -74,6 +75,18 @@ export class Tree<A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<Tree<A>> => {
+  const show = (t: Tree<A>): string => {
+    return `new Tree(${S.show(t.value)}, [${t.forest.map(show).join(', ')}])`
+  }
+  return {
+    show
+  }
+}
+
 const map = <A, B>(fa: Tree<A>, f: (a: A) => B): Tree<B> => {
   return fa.map(f)
 }
diff --git a/src/Tuple.ts b/src/Tuple.ts
index 1ff985a8..593b5cfc 100644
--- a/src/Tuple.ts
+++ b/src/Tuple.ts
@@ -18,6 +18,7 @@ import { Semigroup } from './Semigroup'
 import { Semigroupoid2 } from './Semigroupoid'
 import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v2 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -70,6 +71,15 @@ export class Tuple<L, A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Tuple<L, A>> => {
+  return {
+    show: t => `new Tuple(${SL.show(t.fst)}, ${SA.show(t.snd)})`
+  }
+}
+
 const fst = <L, A>(fa: Tuple<L, A>): L => {
   return fa.fst
 }
diff --git a/src/Validation.ts b/src/Validation.ts
index c6057c72..e92f1cec 100644
--- a/src/Validation.ts
+++ b/src/Validation.ts
@@ -23,6 +23,7 @@ import { Setoid, fromEquals } from './Setoid'
 import { Traversable2v2 } from './Traversable2v'
 import { Witherable2C } from './Witherable'
 import { MonadThrow2C } from './MonadThrow'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT2<L, A> {
@@ -166,6 +167,15 @@ export class Success<L, A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <L, A>(SL: Show<L>, SA: Show<A>): Show<Validation<L, A>> => {
+  return {
+    show: e => e.fold(l => `failure(${SL.show(l)})`, a => `success(${SA.show(a)})`)
+  }
+}
+
 /**
  * @since 1.0.0
  */
diff --git a/src/Zipper.ts b/src/Zipper.ts
index bbac08a0..8cf30c07 100644
--- a/src/Zipper.ts
+++ b/src/Zipper.ts
@@ -11,7 +11,7 @@
  * - https://github.com/scalaz/scalaz/blob/series/7.3.x/core/src/main/scala/scalaz/Zipper.scala
  */
 import { Applicative, Applicative1 } from './Applicative'
-import { array, cons, drop, empty, isEmpty, isOutOfBound, snoc, take } from './Array'
+import { array, cons, drop, empty, isEmpty, isOutOfBound, snoc, take, getShow as getArrayShow } from './Array'
 import { Comonad1 } from './Comonad'
 import { Foldable2v1 } from './Foldable2v'
 import { decrement, increment, toString } from './function'
@@ -22,6 +22,7 @@ import { NonEmptyArray as NonEmptyArray2v } from './NonEmptyArray2v'
 import { none, Option, some } from './Option'
 import { Semigroup } from './Semigroup'
 import { Traversable2v1 } from './Traversable2v'
+import { Show } from './Show'
 
 declare module './HKT' {
   interface URI2HKT<A> {
@@ -176,6 +177,16 @@ export class Zipper<A> {
   }
 }
 
+/**
+ * @since 1.17.0
+ */
+export const getShow = <A>(S: Show<A>): Show<Zipper<A>> => {
+  const SA = getArrayShow(S)
+  return {
+    show: z => `new Zipper(${SA.show(z.lefts)}, ${S.show(z.focus)}, ${SA.show(z.rights)})`
+  }
+}
+
 /**
  * @since 1.9.0
  */
diff --git a/src/index.ts b/src/index.ts
index 73c408bc..e4e7f697 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -154,6 +154,8 @@ import * as set from './Set'
 export { set }
 import * as setoid from './Setoid'
 export { setoid }
+import * as show from './Show'
+export { show }
 import * as state from './State'
 export { state }
 import * as stateT from './StateT'


Test patch:
diff --git a/test/Array.ts b/test/Array.ts
index 11a271bc..c29f3abe 100644
--- a/test/Array.ts
+++ b/test/Array.ts
@@ -65,7 +65,8 @@ import {
   difference,
   unsafeUpdateAt,
   findFirstMap,
-  findLastMap
+  findLastMap,
+  getShow
 } from '../src/Array'
 import { left, right } from '../src/Either'
 import { fold as foldMonoid, monoidSum, monoidString } from '../src/Monoid'
@@ -76,6 +77,7 @@ import { identity, tuple, constTrue, Predicate } from '../src/function'
 import * as I from '../src/Identity'
 import * as F from '../src/Foldable'
 import * as C from '../src/Const'
+import { showString } from '../src/Show'
 
 const p = (n: number) => n > 2
 
@@ -773,4 +775,11 @@ describe('Array', () => {
     const res = array.map([1, 2], f)
     assert.deepStrictEqual(res, ['1', '2'])
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show([]), `[]`)
+    assert.strictEqual(S.show(['a']), `["a"]`)
+    assert.strictEqual(S.show(['a', 'b']), `["a", "b"]`)
+  })
 })
diff --git a/test/Const.ts b/test/Const.ts
index fd73ad31..90624803 100644
--- a/test/Const.ts
+++ b/test/Const.ts
@@ -1,8 +1,9 @@
 import * as assert from 'assert'
-import { Const, getApply, getSetoid, const_, getApplicative } from '../src/Const'
+import { Const, getApply, getSetoid, const_, getApplicative, getShow } from '../src/Const'
 import { semigroupString } from '../src/Semigroup'
 import { setoidNumber } from '../src/Setoid'
 import { monoidString } from '../src/Monoid'
+import { showString } from '../src/Show'
 
 describe('Const', () => {
   it('map', () => {
@@ -46,4 +47,9 @@ describe('Const', () => {
     const fa = new Const<string, (n: number) => number>('foo')
     assert.deepStrictEqual(F.ap(fa, new Const('bar')), new Const<string, unknown>('foobar'))
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show(new Const<string, number>('a')), `new Const("a")`)
+  })
 })
diff --git a/test/Either.ts b/test/Either.ts
index aab7beda..04f46411 100644
--- a/test/Either.ts
+++ b/test/Either.ts
@@ -23,7 +23,8 @@ import {
   tryCatch2v,
   toError,
   parseJSON,
-  stringifyJSON
+  stringifyJSON,
+  getShow
 } from '../src/Either'
 import * as F from '../src/Foldable'
 import { identity } from '../src/function'
@@ -34,6 +35,7 @@ import { semigroupSum } from '../src/Semigroup'
 import { setoidNumber, setoidString } from '../src/Setoid'
 import * as T from '../src/Traversable'
 import { failure, success } from '../src/Validation'
+import { showString } from '../src/Show'
 
 describe('Either', () => {
   it('fold', () => {
@@ -525,4 +527,10 @@ describe('Either', () => {
     const person: Person = { name: 'Giulio', age: 45 }
     assert.deepStrictEqual(stringifyJSON(person, toError).value, '{"name":"Giulio","age":45}')
   })
+
+  it('getShow', () => {
+    const S = getShow(showString, showString)
+    assert.strictEqual(S.show(left('a')), `left("a")`)
+    assert.strictEqual(S.show(right('a')), `right("a")`)
+  })
 })
diff --git a/test/Identity.ts b/test/Identity.ts
index a1d8a564..78c38281 100644
--- a/test/Identity.ts
+++ b/test/Identity.ts
@@ -7,6 +7,7 @@ import { monoidString } from '../src/Monoid'
 import { none, option, some } from '../src/Option'
 import { setoidNumber } from '../src/Setoid'
 import * as T from '../src/Traversable'
+import { showString } from '../src/Show'
 
 describe('Identity', () => {
   it('map', () => {
@@ -125,4 +126,9 @@ describe('Identity', () => {
   it('orElse', () => {
     assert.deepStrictEqual(I.identity.of(123).orElse(() => I.identity.of(456)), I.identity.of(123))
   })
+
+  it('getShow', () => {
+    const S = I.getShow(showString)
+    assert.strictEqual(S.show(new I.Identity('a')), `new Identity("a")`)
+  })
 })
diff --git a/test/Map.ts b/test/Map.ts
index 6cfffb9b..5a66a105 100644
--- a/test/Map.ts
+++ b/test/Map.ts
@@ -9,6 +9,7 @@ import { array } from '../src/Array'
 import { Either, left, right } from '../src/Either'
 import * as I from '../src/Identity'
 import { contramap, ordString, fromCompare, ordNumber } from '../src/Ord'
+import { showString, getStructShow, Show } from '../src/Show'
 
 interface User {
   id: string
@@ -584,4 +585,15 @@ describe('Map', () => {
     assert.deepStrictEqual(fromFoldableS([[{ id: 'a' }, 1], [{ id: 'a' }, 2]], (existing, _) => existing), a1)
     assert.deepStrictEqual(fromFoldableS([[{ id: 'a' }, 1], [{ id: 'a' }, 2]], (_, a) => a), a2)
   })
+
+  it('getShow', () => {
+    const showUser: Show<User> = getStructShow({ id: showString })
+    const S = M.getShow(showUser, showString)
+    const m1 = new Map<User, string>([])
+    assert.strictEqual(S.show(m1), `new Map([])`)
+    const m2 = new Map<User, string>([[{ id: 'a' }, 'b']])
+    assert.strictEqual(S.show(m2), `new Map([[{ id: "a" }, "b"]])`)
+    const m3 = new Map<User, string>([[{ id: 'a' }, 'b'], [{ id: 'c' }, 'd']])
+    assert.strictEqual(S.show(m3), `new Map([[{ id: "a" }, "b"], [{ id: "c" }, "d"]])`)
+  })
 })
diff --git a/test/NonEmptyArray2v.ts b/test/NonEmptyArray2v.ts
index dcf0384b..60efbb79 100644
--- a/test/NonEmptyArray2v.ts
+++ b/test/NonEmptyArray2v.ts
@@ -27,7 +27,8 @@ import {
   cons,
   snoc,
   modifyAt,
-  copy
+  copy,
+  getShow
 } from '../src/NonEmptyArray2v'
 import { none, option, some, isSome } from '../src/Option'
 import { ordNumber } from '../src/Ord'
@@ -37,6 +38,7 @@ import * as T from '../src/Traversable'
 import * as I from '../src/Identity'
 import * as C from '../src/Const'
 import { setoidNumber } from '../src/Setoid'
+import { showString } from '../src/Show'
 
 describe.only('NonEmptyArray2v', () => {
   it('make', () => {
@@ -404,4 +406,10 @@ describe.only('NonEmptyArray2v', () => {
   it('snoc', () => {
     assert.deepStrictEqual(snoc([1, 2, 3], 4), [1, 2, 3, 4])
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show(make<string>('a', [])), `make("a", [])`)
+    assert.strictEqual(S.show(make<string>('a', ['b', 'c'])), `make("a", ["b", "c"])`)
+  })
 })
diff --git a/test/Option.ts b/test/Option.ts
index 6b8a6234..a150077c 100644
--- a/test/Option.ts
+++ b/test/Option.ts
@@ -20,7 +20,8 @@ import {
   tryCatch,
   getRefinement,
   getApplySemigroup,
-  getApplyMonoid
+  getApplyMonoid,
+  getShow
 } from '../src/Option'
 import { ordString } from '../src/Ord'
 import { semigroupString, semigroupSum } from '../src/Semigroup'
@@ -29,6 +30,7 @@ import { identity } from '../src/function'
 import { Identity, identity as I } from '../src/Identity'
 import { monoidSum, monoidString } from '../src/Monoid'
 import * as F from '../src/Foldable'
+import { showString } from '../src/Show'
 
 const p = (n: number): boolean => n > 2
 
@@ -426,4 +428,10 @@ describe('Option', () => {
     assert.strictEqual(isA({ type: 'A' }), true)
     assert.strictEqual(isA({ type: 'B' }), false)
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show(some('a')), `some("a")`)
+    assert.strictEqual(S.show(none), `none`)
+  })
 })
diff --git a/test/Pair.ts b/test/Pair.ts
index a887c693..c2ef0e2b 100644
--- a/test/Pair.ts
+++ b/test/Pair.ts
@@ -4,10 +4,11 @@ import { identity } from '../src/function'
 import { monoidString } from '../src/Monoid'
 import { none, option, some } from '../src/Option'
 import { ordNumber } from '../src/Ord'
-import { getMonoid, getOrd, getSemigroup, getSetoid, Pair, pair } from '../src/Pair'
+import { getMonoid, getOrd, getSemigroup, getSetoid, Pair, pair, getShow } from '../src/Pair'
 import { semigroupString } from '../src/Semigroup'
 import { setoidNumber } from '../src/Setoid'
 import * as T from '../src/Traversable'
+import { showString } from '../src/Show'
 
 describe('Pair', () => {
   it('first', () => {
@@ -115,4 +116,9 @@ describe('Pair', () => {
     assert.deepStrictEqual(S.concat(new Pair('a', 'b'), new Pair('', '')), new Pair('a', 'b'))
     assert.deepStrictEqual(S.concat(new Pair('', ''), new Pair('a', 'b')), new Pair('a', 'b'))
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show(new Pair('a', 'b')), `new Pair("a", "b")`)
+  })
 })
diff --git a/test/Record.ts b/test/Record.ts
index f397af7e..ba52fb05 100644
--- a/test/Record.ts
+++ b/test/Record.ts
@@ -8,6 +8,7 @@ import { setoidNumber } from '../src/Setoid'
 import { array, zip } from '../src/Array'
 import { left, right } from '../src/Either'
 import * as I from '../src/Identity'
+import { showString } from '../src/Show'
 
 const p = (n: number) => n > 2
 
@@ -297,4 +298,11 @@ describe('Record', () => {
       id2: { id: 'id2', name: 'name2' }
     })
   })
+
+  it('getShow', () => {
+    const S = R.getShow(showString)
+    assert.strictEqual(S.show({}), `{}`)
+    assert.strictEqual(S.show({ a: 'a' }), `{ "a": "a" }`)
+    assert.strictEqual(S.show({ a: 'a', b: 'b' }), `{ "a": "a", "b": "b" }`)
+  })
 })
diff --git a/test/Set.ts b/test/Set.ts
index da2ecdbe..2f86f220 100644
--- a/test/Set.ts
+++ b/test/Set.ts
@@ -27,11 +27,13 @@ import {
   compact,
   separate,
   filterMap,
-  foldMap
+  foldMap,
+  getShow
 } from '../src/Set'
 import { Setoid, setoidNumber, setoidString, contramap, getStructSetoid } from '../src/Setoid'
 import { none, some as optionSome } from '../src/Option'
 import { getArrayMonoid } from '../src/Monoid'
+import { showString } from '../src/Show'
 
 const gte2 = (n: number) => n >= 2
 
@@ -265,4 +267,14 @@ describe('Set', () => {
     const S: Setoid<R> = contramap(x => x.id, setoidString)
     assert.deepStrictEqual(filterMap(S)(new Set([{ id: 'a' }, { id: 'a' }]), optionSome), new Set([{ id: 'a' }]))
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    const s1 = new Set<string>([])
+    assert.strictEqual(S.show(s1), `new Set([])`)
+    const s2 = new Set<string>(['a'])
+    assert.strictEqual(S.show(s2), `new Set(["a"])`)
+    const s3 = new Set<string>(['a', 'b'])
+    assert.strictEqual(S.show(s3), `new Set(["a", "b"])`)
+  })
 })
diff --git a/test/Show.ts b/test/Show.ts
new file mode 100644
index 00000000..067d0567
--- /dev/null
+++ b/test/Show.ts
@@ -0,0 +1,29 @@
+import * as assert from 'assert'
+import { showString, showNumber, showBoolean, getStructShow, getTupleShow } from '../src/Show'
+
+describe('Show', () => {
+  it('showString', () => {
+    const S = showString
+    assert.strictEqual(S.show('a'), '"a"')
+  })
+
+  it('showNumber', () => {
+    const S = showNumber
+    assert.strictEqual(S.show(1), '1')
+  })
+
+  it('showBoolean', () => {
+    const S = showBoolean
+    assert.strictEqual(S.show(true), 'true')
+  })
+
+  it('getStructShow', () => {
+    const S = getStructShow({ a: showString, b: showNumber })
+    assert.strictEqual(S.show({ a: 'a', b: 1 }), '{ a: "a", b: 1 }')
+  })
+
+  it('getTupleShow', () => {
+    const S = getTupleShow(showString, showNumber)
+    assert.strictEqual(S.show(['a', 1]), '["a", 1]')
+  })
+})
diff --git a/test/StrMap.ts b/test/StrMap.ts
index dc8f4639..98f58e54 100644
--- a/test/StrMap.ts
+++ b/test/StrMap.ts
@@ -26,9 +26,11 @@ import {
   singleton,
   isSubdictionary,
   collect,
-  elem
+  elem,
+  getShow
 } from '../src/StrMap'
 import * as T from '../src/Traversable'
+import { showString } from '../src/Show'
 
 const p = (n: number) => n > 2
 
@@ -344,4 +346,14 @@ describe('StrMap', () => {
     assert.strictEqual(elem(setoidNumber)(1, x), true)
     assert.strictEqual(elem(setoidNumber)(3, x), false)
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    const s1 = new StrMap<string>({})
+    assert.strictEqual(S.show(s1), `new StrMap({})`)
+    const s2 = new StrMap({ a: 'a' })
+    assert.strictEqual(S.show(s2), `new StrMap({ "a": "a" })`)
+    const s3 = new StrMap({ a: 'a', b: 'b' })
+    assert.strictEqual(S.show(s3), `new StrMap({ "a": "a", "b": "b" })`)
+  })
 })
diff --git a/test/These.ts b/test/These.ts
index 500c735f..9c364ca3 100644
--- a/test/These.ts
+++ b/test/These.ts
@@ -24,10 +24,12 @@ import {
   theseThis,
   theseThat,
   fromOptions,
-  fromEither
+  fromEither,
+  getShow
 } from '../src/These'
 import * as T from '../src/Traversable'
 import { left, right } from '../src/Either'
+import { showString } from '../src/Show'
 
 describe('These', () => {
   it('getSetoid', () => {
@@ -267,4 +269,11 @@ describe('These', () => {
     assert.strictEqual(foldr(x3, init1, f1), 'a')
     assert.strictEqual(foldr(x3, init1, f1), old(x3, init1, f1))
   })
+
+  it('getShow', () => {
+    const S = getShow(showString, showString)
+    assert.strictEqual(S.show(this_('a')), `this_("a")`)
+    assert.strictEqual(S.show(that('a')), `that("a")`)
+    assert.strictEqual(S.show(both('a', 'b')), `both("a", "b")`)
+  })
 })
diff --git a/test/Tree.ts b/test/Tree.ts
index 9657d687..cbdb94ea 100644
--- a/test/Tree.ts
+++ b/test/Tree.ts
@@ -5,7 +5,8 @@ import * as I from '../src/Identity'
 import { monoidString } from '../src/Monoid'
 import { setoidNumber, Setoid, contramap } from '../src/Setoid'
 import * as T from '../src/Traversable'
-import { drawTree, getSetoid, Tree, tree, unfoldTree, unfoldTreeM, elem } from '../src/Tree'
+import { drawTree, getSetoid, Tree, tree, unfoldTree, unfoldTreeM, elem, getShow } from '../src/Tree'
+import { showString } from '../src/Show'
 
 describe('Tree', () => {
   it('map', () => {
@@ -182,4 +183,12 @@ describe('Tree', () => {
     assert.strictEqual(elem(S)({ id: 4 }, users), true)
     assert.strictEqual(elem(S)({ id: 5 }, users), false)
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    const t1 = new Tree('a', [])
+    assert.strictEqual(S.show(t1), `new Tree("a", [])`)
+    const t2 = new Tree('a', [new Tree('b', []), new Tree('c', [])])
+    assert.strictEqual(S.show(t2), `new Tree("a", [new Tree("b", []), new Tree("c", [])])`)
+  })
 })
diff --git a/test/Tuple.ts b/test/Tuple.ts
index ba0990aa..f8617d2a 100644
--- a/test/Tuple.ts
+++ b/test/Tuple.ts
@@ -18,8 +18,10 @@ import {
   getSemigroup,
   getSetoid,
   Tuple,
-  tuple
+  tuple,
+  getShow
 } from '../src/Tuple'
+import { showString } from '../src/Show'
 
 describe('Tuple', () => {
   it('compose', () => {
@@ -211,4 +213,9 @@ describe('Tuple', () => {
     assert.strictEqual(S.equals(new Tuple(1, true), new Tuple(2, true)), false)
     assert.strictEqual(S.equals(new Tuple(1, true), new Tuple(1, false)), false)
   })
+
+  it('getShow', () => {
+    const S = getShow(showString, showString)
+    assert.strictEqual(S.show(new Tuple('a', 'b')), `new Tuple("a", "b")`)
+  })
 })
diff --git a/test/Validation.ts b/test/Validation.ts
index c367096a..ae997634 100644
--- a/test/Validation.ts
+++ b/test/Validation.ts
@@ -25,8 +25,10 @@ import {
   success,
   validation,
   tryCatch,
-  getMonadThrow
+  getMonadThrow,
+  getShow
 } from '../src/Validation'
+import { showString } from '../src/Show'
 
 const p = (n: number): boolean => n > 2
 
@@ -355,4 +357,10 @@ describe('Validation', () => {
       assert.deepStrictEqual(M.fromOption(some(1), 'error'), success(1))
     })
   })
+
+  it('getShow', () => {
+    const S = getShow(showString, showString)
+    assert.strictEqual(S.show(failure('a')), `failure("a")`)
+    assert.strictEqual(S.show(success('a')), `success("a")`)
+  })
 })
diff --git a/test/Zipper.ts b/test/Zipper.ts
index ab0bb19a..30b0197e 100644
--- a/test/Zipper.ts
+++ b/test/Zipper.ts
@@ -14,8 +14,10 @@ import {
   getSemigroup,
   Zipper,
   zipper,
-  fromNonEmptyArray2v
+  fromNonEmptyArray2v,
+  getShow
 } from '../src/Zipper'
+import { showString } from '../src/Show'
 
 const len = (s: string): number => s.length
 const prepend = (a: string) => (s: string): string => a + s
@@ -221,4 +223,13 @@ describe('Zipper', () => {
       )
     )
   })
+
+  it('getShow', () => {
+    const S = getShow(showString)
+    assert.strictEqual(S.show(new Zipper([], 'a', [])), 'new Zipper([], "a", [])')
+    assert.strictEqual(S.show(new Zipper(['b'], 'a', [])), 'new Zipper(["b"], "a", [])')
+    assert.strictEqual(S.show(new Zipper(['b', 'c'], 'a', [])), 'new Zipper(["b", "c"], "a", [])')
+    assert.strictEqual(S.show(new Zipper(['b', 'c'], 'a', ['d'])), 'new Zipper(["b", "c"], "a", ["d"])')
+    assert.strictEqual(S.show(new Zipper(['b', 'c'], 'a', ['d', 'e'])), 'new Zipper(["b", "c"], "a", ["d", "e"])')
+  })
 })