Repository: sanctuary-js/sanctuary
Pull request #620 (2019-04-05 14:49:51)

maybe, either: unify S.encase and S.encaseEither
There's little value in having both `S.encase` and `S.encaseEither`: every use of the former could be rewritten in terms of the latter with help from [`S.eitherToMaybe`][1]. Thus we should remove `S.encase`.

This vacates the desirable name, so we should then rename `S.encaseEither`.

Finally, we should drop the `Error -> l` argument as it is unnecessary in the presence of [`S.mapLeft`][2].

In summary:

```haskell
--  Before
encase       ::                 (a -> b) -> a -> Maybe b
encaseEither :: (Error -> l) -> (a -> r) -> a -> Either l r

--  After
encase       ::                 (a -> b) -> a -> Either Error b
```

In conjunction with #618, this will reduce the number of “encase” functions from six to one. :)


[1]: https://sanctuary.js.org/#eitherToMaybe
[2]: https://sanctuary.js.org/#mapLeft



Patch:
diff --git a/index.js b/index.js
index d27c5cb..90d86cf 100644
--- a/index.js
+++ b/index.js
@@ -494,7 +494,6 @@
   var d = $.TypeVariable ('d');
   var e = $.TypeVariable ('e');
   var g = $.TypeVariable ('g');
-  var l = $.TypeVariable ('l');
   var r = $.TypeVariable ('r');
 
   //  :: Type -> Type
@@ -2306,31 +2305,6 @@
     impl: B (B (justs)) (map)
   };
 
-  //# encase :: (a -> b) -> a -> Maybe b
-  //.
-  //. Takes a unary function `f` which may throw and a value `x` of any type,
-  //. and applies `f` to `x` inside a `try` block. If an exception is caught,
-  //. the return value is Nothing; otherwise the return value is Just the
-  //. result of applying `f` to `x`.
-  //.
-  //. See also [`encaseEither`](#encaseEither).
-  //.
-  //. ```javascript
-  //. > S.encase (eval) ('1 + 1')
-  //. Just (2)
-  //.
-  //. > S.encase (eval) ('1 +')
-  //. Nothing
-  //. ```
-  function encase(f) {
-    return B (eitherToMaybe) (encaseEither (I) (f));
-  }
-  _.encase = {
-    consts: {},
-    types: [Fn (a) (b), a, $Maybe (b)],
-    impl: encase
-  };
-
   //# maybeToEither :: a -> Maybe b -> Either a b
   //.
   //. Converts a Maybe to an Either. Nothing becomes a Left (containing the
@@ -2575,41 +2549,30 @@
     impl: tagBy
   };
 
-  //# encaseEither :: (Error -> l) -> (a -> r) -> a -> Either l r
+  //# encase :: (a -> b) -> a -> Either Error b
   //.
-  //. Takes two unary functions, `f` and `g`, the second of which may throw,
-  //. and a value `x` of any type. Applies `g` to `x` inside a `try` block.
-  //. If an exception is caught, the return value is a Left containing the
-  //. result of applying `f` to the caught Error object; otherwise the return
-  //. value is a Right containing the result of applying `g` to `x`.
-  //.
-  //. See also [`encase`](#encase).
+  //. Takes a function that may throw and returns a pure function.
   //.
   //. ```javascript
-  //. > S.encaseEither (S.I) (JSON.parse) ('["foo","bar","baz"]')
+  //. > S.encase (JSON.parse) ('["foo","bar","baz"]')
   //. Right (['foo', 'bar', 'baz'])
   //.
-  //. > S.encaseEither (S.I) (JSON.parse) ('[')
+  //. > S.encase (JSON.parse) ('[')
   //. Left (new SyntaxError ('Unexpected end of JSON input'))
-  //.
-  //. > S.encaseEither (S.prop ('message')) (JSON.parse) ('[')
-  //. Left ('Unexpected end of JSON input')
   //. ```
-  function encaseEither(f) {
-    return function(g) {
-      return function(x) {
-        try {
-          return Right (g (x));
-        } catch (err) {
-          return Left (f (err));
-        }
-      };
+  function encase(f) {
+    return function(x) {
+      try {
+        return Right (f (x));
+      } catch (err) {
+        return Left (err);
+      }
     };
   }
-  _.encaseEither = {
+  _.encase = {
     consts: {},
-    types: [Fn ($.Error) (l), Fn (a) (r), a, $Either (l) (r)],
-    impl: encaseEither
+    types: [Fn (a) (b), a, $Either ($.Error) (b)],
+    impl: encase
   };
 
   //# eitherToMaybe :: Either a b -> Maybe b
@@ -4464,7 +4427,7 @@
   //. Just ([1, 2, 3])
   //. ```
   function parseJson(pred) {
-    return B (filter (pred)) (encase (JSON.parse));
+    return B (filter (pred)) (B (eitherToMaybe) (encase (JSON.parse)));
   }
   _.parseJson = {
     consts: {},


Test patch:
diff --git a/test/encase.js b/test/encase.js
index 5850c3a..4b208d6 100644
--- a/test/encase.js
+++ b/test/encase.js
@@ -12,24 +12,24 @@ test ('encase', () => {
 
   eq (typeof S.encase) ('function');
   eq (S.encase.length) (1);
-  eq (S.show (S.encase)) ('encase :: (a -> b) -> a -> Maybe b');
+  eq (S.show (S.encase)) ('encase :: (a -> b) -> a -> Either Error b');
 
   //    safeFactorial :: Number -> Maybe Number
   const safeFactorial = S.encase (factorial);
 
-  eq (safeFactorial (5)) (S.Just (120));
-  eq (safeFactorial (-1)) (S.Nothing);
+  eq (safeFactorial (5)) (S.Right (120));
+  eq (safeFactorial (-1)) (S.Left (new Error ('Cannot determine factorial of negative number')));
 
   //    safeRem :: Number -> Number -> Maybe Number
   const safeRem = S.compose (S.encase) (rem);
 
-  eq (safeRem (42) (5)) (S.Just (2));
-  eq (safeRem (42) (0)) (S.Nothing);
+  eq (safeRem (42) (5)) (S.Right (2));
+  eq (safeRem (42) (0)) (S.Left (new Error ('Cannot divide by zero')));
 
   //    safeArea :: Number -> Number -> Number -> Maybe Number
   const safeArea = S.compose (S.compose (S.encase)) (area);
 
-  eq (safeArea (3) (4) (5)) (S.Just (6));
-  eq (safeArea (2) (2) (5)) (S.Nothing);
+  eq (safeArea (3) (4) (5)) (S.Right (6));
+  eq (safeArea (2) (2) (5)) (S.Left (new Error ('Impossible triangle')));
 
 });
diff --git a/test/encaseEither.js b/test/encaseEither.js
deleted file mode 100644
index 1fb50e9..0000000
--- a/test/encaseEither.js
+++ /dev/null
@@ -1,41 +0,0 @@
-'use strict';
-
-const S = require ('..');
-
-const area = require ('./internal/area');
-const eq = require ('./internal/eq');
-const factorial = require ('./internal/factorial');
-const rem = require ('./internal/rem');
-
-
-test ('encaseEither', () => {
-
-  eq (typeof S.encaseEither) ('function');
-  eq (S.encaseEither.length) (1);
-  eq (S.show (S.encaseEither)) ('encaseEither :: (Error -> l) -> (a -> r) -> a -> Either l r');
-
-  //    safeFactorial :: Number -> Either Error Number
-  const safeFactorial = S.encaseEither (S.I) (factorial);
-
-  eq (safeFactorial (5)) (S.Right (120));
-  eq (safeFactorial (-1)) (S.Left (new Error ('Cannot determine factorial of negative number')));
-  eq (S.mapLeft (S.prop ('message')) (safeFactorial (-1)))
-     (S.Left ('Cannot determine factorial of negative number'));
-
-  //    safeRem :: Number -> Number -> Either Error Number
-  const safeRem = S.compose (S.encaseEither (S.I)) (rem);
-
-  eq (safeRem (42) (5)) (S.Right (2));
-  eq (safeRem (42) (0)) (S.Left (new Error ('Cannot divide by zero')));
-  eq (S.mapLeft (S.prop ('message')) (safeRem (42) (0)))
-     (S.Left ('Cannot divide by zero'));
-
-  //    safeArea :: Number -> Number -> Number -> Either Error Number
-  const safeArea = S.compose (S.compose (S.encaseEither (S.I))) (area);
-
-  eq (safeArea (3) (4) (5)) (S.Right (6));
-  eq (safeArea (2) (2) (5)) (S.Left (new Error ('Impossible triangle')));
-  eq (S.mapLeft (S.prop ('message')) (safeArea (2) (2) (5)))
-     (S.Left ('Impossible triangle'));
-
-});