Repository: gcanti/fp-ts
Pull request #809 (2019-04-03 03:47:37)

add Validation.tryCatch


Patch:
diff --git a/docs/modules/Array.ts.md b/docs/modules/Array.ts.md
index 5f8994d0..1fb2a418 100644
--- a/docs/modules/Array.ts.md
+++ b/docs/modules/Array.ts.md
@@ -267,12 +267,12 @@ Added in v1.10.0
 
 # cons (function)
 
-Attaches an element to the front of an array, creating a new array
+Attaches an element to the front of an array, creating a new non empty array
 
 **Signature**
 
 ```ts
-export const cons = <A>(a: A, as: Array<A>): Array<A> => ...
+export const cons = <A>(a: A, as: Array<A>): NonEmptyArray<A> => ...
 ```
 
 **Example**
@@ -1199,12 +1199,12 @@ Added in v1.1.0
 
 # snoc (function)
 
-Append an element to the end of an array, creating a new array
+Append an element to the end of an array, creating a new non empty array
 
 **Signature**
 
 ```ts
-export const snoc = <A>(as: Array<A>, a: A): Array<A> => ...
+export const snoc = <A>(as: Array<A>, a: A): NonEmptyArray<A> => ...
 ```
 
 **Example**
diff --git a/docs/modules/Console.ts.md b/docs/modules/Console.ts.md
index cb980c2f..8672db49 100644
--- a/docs/modules/Console.ts.md
+++ b/docs/modules/Console.ts.md
@@ -24,7 +24,7 @@ Adapted from https://github.com/purescript/purescript-console
 **Signature**
 
 ```ts
-export const error = (s: any): IO<void> => ...
+export const error = (s: unknown): IO<void> => ...
 ```
 
 Added in v1.0.0
@@ -34,7 +34,7 @@ Added in v1.0.0
 **Signature**
 
 ```ts
-export const info = (s: any): IO<void> => ...
+export const info = (s: unknown): IO<void> => ...
 ```
 
 Added in v1.0.0
@@ -44,7 +44,7 @@ Added in v1.0.0
 **Signature**
 
 ```ts
-export const log = (s: any): IO<void> => ...
+export const log = (s: unknown): IO<void> => ...
 ```
 
 Added in v1.0.0
@@ -54,7 +54,7 @@ Added in v1.0.0
 **Signature**
 
 ```ts
-export const warn = (s: any): IO<void> => ...
+export const warn = (s: unknown): IO<void> => ...
 ```
 
 Added in v1.0.0
diff --git a/docs/modules/NonEmptyArray2v.ts.md b/docs/modules/NonEmptyArray2v.ts.md
index 424f6866..96de57e6 100644
--- a/docs/modules/NonEmptyArray2v.ts.md
+++ b/docs/modules/NonEmptyArray2v.ts.md
@@ -15,7 +15,9 @@ Data structure which represents non-empty arrays
 - [NonEmptyArray (interface)](#nonemptyarray-interface)
 - [URI (type alias)](#uri-type-alias)
 - [URI (constant)](#uri-constant)
+- [cons (constant)](#cons-constant)
 - [nonEmptyArray (constant)](#nonemptyarray-constant)
+- [snoc (constant)](#snoc-constant)
 - [filter (function)](#filter-function)
 - [filterWithIndex (function)](#filterwithindex-function)
 - [findFirst (function)](#findfirst-function)
@@ -72,6 +74,26 @@ export type URI = typeof URI
 export const URI = ...
 ```
 
+# cons (constant)
+
+Append an element to the front of an array, creating a new non empty array
+
+**Signature**
+
+```ts
+export const cons: <A>(a: A, as: Array<A>) => NonEmptyArray<A> = ...
+```
+
+**Example**
+
+```ts
+import { cons } from 'fp-ts/lib/NonEmptyArray2v'
+
+assert.deepStrictEqual(cons(1, [2, 3, 4]), [1, 2, 3, 4])
+```
+
+Added in v1.16.0
+
 # nonEmptyArray (constant)
 
 **Signature**
@@ -86,6 +108,26 @@ export const nonEmptyArray: Monad1<URI> &
 
 Added in v1.15.0
 
+# snoc (constant)
+
+Append an element to the end of an array, creating a new non empty array
+
+**Signature**
+
+```ts
+export const snoc: <A>(as: Array<A>, a: A) => NonEmptyArray<A> = ...
+```
+
+**Example**
+
+```ts
+import { snoc } from 'fp-ts/lib/NonEmptyArray2v'
+
+assert.deepStrictEqual(snoc([1, 2, 3], 4), [1, 2, 3, 4])
+```
+
+Added in v1.16.0
+
 # filter (function)
 
 **Signature**
diff --git a/docs/modules/Validation.ts.md b/docs/modules/Validation.ts.md
index 9c067e58..ef1366e3 100644
--- a/docs/modules/Validation.ts.md
+++ b/docs/modules/Validation.ts.md
@@ -61,6 +61,7 @@ Adapted from https://github.com/purescript/purescript-validation
 - [isFailure (function)](#isfailure-function)
 - [isSuccess (function)](#issuccess-function)
 - [success (function)](#success-function)
+- [tryCatch (function)](#trycatch-function)
 
 ---
 
@@ -557,3 +558,36 @@ export const success = <L, A>(a: A): Validation<L, A> => ...
 ```
 
 Added in v1.0.0
+
+# tryCatch (function)
+
+Constructs a new `Validation` from a function that might throw
+
+**Signature**
+
+```ts
+export const tryCatch = <L, A>(f: Lazy<A>, onError: (e: unknown) => L): Validation<L, A> => ...
+```
+
+**Example**
+
+```ts
+import { Validation, failure, success, tryCatch } from 'fp-ts/lib/Validation'
+
+const unsafeHead = <A>(as: Array<A>): A => {
+  if (as.length > 0) {
+    return as[0]
+  } else {
+    throw new Error('empty array')
+  }
+}
+
+const head = <A>(as: Array<A>): Validation<Error, A> => {
+  return tryCatch(() => unsafeHead(as), e => (e instanceof Error ? e : new Error('unknown error')))
+}
+
+assert.deepStrictEqual(head([]), failure(new Error('empty array')))
+assert.deepStrictEqual(head([1, 2, 3]), success(1))
+```
+
+Added in v1.16.0
diff --git a/src/Console.ts b/src/Console.ts
index 25d945bb..51ffe06c 100644
--- a/src/Console.ts
+++ b/src/Console.ts
@@ -6,27 +6,27 @@ import { IO } from './IO'
 /**
  * @since 1.0.0
  */
-export const log = (s: any): IO<void> => {
+export const log = (s: unknown): IO<void> => {
   return new IO(() => console.log(s)) // tslint:disable-line:no-console
 }
 
 /**
  * @since 1.0.0
  */
-export const warn = (s: any): IO<void> => {
+export const warn = (s: unknown): IO<void> => {
   return new IO(() => console.warn(s)) // tslint:disable-line:no-console
 }
 
 /**
  * @since 1.0.0
  */
-export const error = (s: any): IO<void> => {
+export const error = (s: unknown): IO<void> => {
   return new IO(() => console.error(s)) // tslint:disable-line:no-console
 }
 
 /**
  * @since 1.0.0
  */
-export const info = (s: any): IO<void> => {
+export const info = (s: unknown): IO<void> => {
   return new IO(() => console.info(s)) // tslint:disable-line:no-console
 }
diff --git a/src/NonEmptyArray2v.ts b/src/NonEmptyArray2v.ts
index 6400b32d..763d30b2 100644
--- a/src/NonEmptyArray2v.ts
+++ b/src/NonEmptyArray2v.ts
@@ -291,7 +291,7 @@ const mapWithIndex = <A, B>(fa: NonEmptyArray<A>, f: (i: number, a: A) => B): No
  *
  * @since 1.16.0
  */
-export const snoc = A.snoc
+export const snoc: <A>(as: Array<A>, a: A) => NonEmptyArray<A> = A.snoc
 
 /**
  * Append an element to the front of an array, creating a new non empty array
@@ -303,7 +303,7 @@ export const snoc = A.snoc
  *
  * @since 1.16.0
  */
-export const cons = A.cons
+export const cons: <A>(a: A, as: Array<A>) => NonEmptyArray<A> = A.cons
 
 /**
  * @since 1.15.0
diff --git a/src/Validation.ts b/src/Validation.ts
index d4212cf9..aef961e7 100644
--- a/src/Validation.ts
+++ b/src/Validation.ts
@@ -12,7 +12,7 @@ import { Compactable2C, Separated } from './Compactable'
 import { Either } from './Either'
 import { Filterable2C } from './Filterable'
 import { Foldable2v2 } from './Foldable2v'
-import { phantom, Predicate, toString, Refinement } from './function'
+import { phantom, Predicate, toString, Refinement, Lazy } from './function'
 import { Functor2 } from './Functor'
 import { HKT } from './HKT'
 import { Monad2C } from './Monad'
@@ -306,6 +306,37 @@ export const fromEither = <L, A>(e: Either<L, A>): Validation<L, A> => {
   return e.isLeft() ? failure(e.value) : success(e.value)
 }
 
+/**
+ * Constructs a new `Validation` from a function that might throw
+ *
+ * @example
+ * import { Validation, failure, success, tryCatch } from 'fp-ts/lib/Validation'
+ *
+ * const unsafeHead = <A>(as: Array<A>): A => {
+ *   if (as.length > 0) {
+ *     return as[0]
+ *   } else {
+ *     throw new Error('empty array')
+ *   }
+ * }
+ *
+ * const head = <A>(as: Array<A>): Validation<Error, A> => {
+ *   return tryCatch(() => unsafeHead(as), e => (e instanceof Error ? e : new Error('unknown error')))
+ * }
+ *
+ * assert.deepStrictEqual(head([]), failure(new Error('empty array')))
+ * assert.deepStrictEqual(head([1, 2, 3]), success(1))
+ *
+ * @since 1.16.0
+ */
+export const tryCatch = <L, A>(f: Lazy<A>, onError: (e: unknown) => L): Validation<L, A> => {
+  try {
+    return success(f())
+  } catch (e) {
+    return failure(onError(e))
+  }
+}
+
 /**
  * @since 1.0.0
  */


Test patch:
diff --git a/test/Validation.ts b/test/Validation.ts
index 1ae19c65..12ac55c6 100644
--- a/test/Validation.ts
+++ b/test/Validation.ts
@@ -23,7 +23,8 @@ import {
   isFailure,
   isSuccess,
   success,
-  validation
+  validation,
+  tryCatch
 } from '../src/Validation'
 
 const p = (n: number): boolean => n > 2
@@ -323,4 +324,21 @@ describe('Validation', () => {
       )
     })
   })
+
+  it('tryCatch', () => {
+    const v1 = tryCatch(
+      () => {
+        throw new Error('foo')
+      },
+      () => 'error'
+    )
+    assert.deepStrictEqual(v1, failure('error'))
+    const v2 = tryCatch(
+      () => {
+        return 1
+      },
+      () => 'error'
+    )
+    assert.deepStrictEqual(v2, success(1))
+  })
 })