Repository: sanctuary-js/sanctuary (js)

Issue:
Can we rework encase to allow any type to be thrown?
Something like this:

```diff
- encase :: (a -> b) -> a -> Either Error b
+ encase :: Throwing e (a -> b) -> a -> Either e b
```

Because I'm getting bitten by the fact that I expect a function to be safe after using `encase`, only to find out that it now throws a TypeError because the function I've encased throws a String.

Pull request description:
either: generalize S.encase to permit a value of any type to be thrown
Closes #646


Patch:
diff --git a/index.js b/index.js
index 94464b6..4f37a8c 100644
--- a/index.js
+++ b/index.js
@@ -480,6 +480,24 @@
   var p = $.BinaryTypeVariable ('p');
   var s = $.BinaryTypeVariable ('s');
 
+  //  Throwing :: Type -> Type -> Type -> Type
+  //
+  //  `Throwing e a b` is the type of functions from `a` to `b` that may
+  //  throw values of type `e`.
+  function Throwing(E) {
+    return function(A) {
+      return function(B) {
+        var T = $.Fn (A) (B);
+        T.format = function(outer, inner) {
+          return outer ('Throwing ' + show (E)) +
+                 outer (' ') + inner ('$1') (show (A)) +
+                 outer (' ') + inner ('$2') (show (B));
+        };
+        return T;
+      };
+    };
+  }
+
   //  TypeRep :: Type -> Type
   var TypeRep = $.UnaryType
     ('TypeRep')
@@ -2398,7 +2416,7 @@
     impl: tagBy
   };
 
-  //# encase :: (a -> b) -> a -> Either Error b
+  //# encase :: Throwing e a b -> a -> Either e b
   //.
   //. Takes a function that may throw and returns a pure function.
   //.
@@ -2420,7 +2438,7 @@
   }
   _.encase = {
     consts: {},
-    types: [$.Fn (a) (b), a, $.Either ($.Error) (b)],
+    types: [Throwing (e) (a) (b), a, $.Either (e) (b)],
     impl: encase
   };
 


Test patch:
diff --git a/test/encase.js b/test/encase.js
index 790fb4d..44e36bd 100644
--- a/test/encase.js
+++ b/test/encase.js
@@ -10,13 +10,13 @@ const rem = require ('./internal/rem');
 
 test ('encase', () => {
 
-  eq (S.show (S.encase)) ('encase :: (a -> b) -> a -> Either Error b');
+  eq (S.show (S.encase)) ('encase :: (Throwing e a b) -> a -> Either e b');
 
   //    safeFactorial :: Number -> Maybe Number
   const safeFactorial = S.encase (factorial);
 
   eq (safeFactorial (5)) (S.Right (120));
-  eq (safeFactorial (-1)) (S.Left (new Error ('Cannot determine factorial of negative number')));
+  eq (safeFactorial (-1)) (S.Left ('Cannot determine factorial of negative number'));
 
   //    safeRem :: Number -> Number -> Maybe Number
   const safeRem = S.compose (S.encase) (rem);
diff --git a/test/internal/factorial.js b/test/internal/factorial.js
index cf2d0a3..f60e153 100644
--- a/test/internal/factorial.js
+++ b/test/internal/factorial.js
@@ -1,9 +1,10 @@
 'use strict';
 
-//    factorial :: Number -> Number !
+//    factorial :: Throwing String Number Number
 module.exports = function factorial(n) {
   if (n < 0) {
-    throw new Error ('Cannot determine factorial of negative number');
+    // eslint-disable-next-line no-throw-literal
+    throw 'Cannot determine factorial of negative number';
   } else if (n === 0) {
     return 1;
   } else {