Repository: sanctuary-js/sanctuary
Pull request #279 (2016-11-12 10:46:03)

logic: make S.and and S.or monomorphic, and remove S.xor
Commit message:

> The first of the three functions to be added was `S.or`, to allow:
>
>     > S.or(S.Nothing, S.Just(42))
>     Just(42)
>
> This is possible in Haskell too:
>
>     > Nothing <|> Just 42
>     Just 42
>
> The `<|>` operator, though, does not accept Boolean operands, as the Bool type does not satisfy the requirements of the Alternative type class.
>
> The Bool type has two monoids:
>
>   - All
>     - `mempty = True`
>     - `mappend = (&&)`
>   - Any
>     - `mempty = False`
>     - `mappend = (||)`
>
> Overloading `S.or` for Boolean arguments requires implicitly selecting All as the Boolean monoid. This necessitates the definition and use of a Sanctuary-specific Monoid-like type class (the standard Monoid type class defined in sanctuary-type-classes rejects Boolean values because `fantasy-land/empty` is not defined for the Boolean type).
>
> This commit updates the type of `S.or` to match that of Haskell's `(||)`:
>
>     S.or :: Boolean -> Boolean -> Boolean
>
> The `<|>` behaviour currently provided by `S.or` is undoubtedly useful, but will be provided by `S.alt` once Sanctuary wrappers are added for the functions defined in sanctuary-type-classes:
>
>     S.alt :: Alt f => f a -> f a -> f a
>
> `S.and` is currently polymorphic for consistency with `S.or` rather than to address any particular need. This commit updates the type of `S.and` to match that of Haskell's `(&&)`:
>
>     S.and :: Boolean -> Boolean -> Boolean
>
> Boolean XOR does not warrant inclusion, so this commit removes `S.xor`.
>
> This commit also removes the `toBoolean` methods which existed solely to allow `S.and`, `S.or`, and `S.xor` to operate on Maybe and Either values.

I've been grappling with this for months. Now that [`alt`][1] exists we can simplify these functions which have been causing me so much trouble. :)

For context, `S.or` was added all the way back in #1, and `S.and` and `S.xor` were added in #26.


[1]: https://github.com/sanctuary-js/sanctuary-type-classes#alt



Patch:
diff --git a/index.js b/index.js
index f9de4df..112358a 100644
--- a/index.js
+++ b/index.js
@@ -284,15 +284,6 @@
     }
   );
 
-  //  Monoid :: TypeClass
-  var Monoid = $.TypeClass(
-    'sanctuary/Monoid',
-    function(x) {
-      return R.contains(R.type(x), ['Array', 'Boolean', 'String']) ||
-             hasMethod('empty')(x);
-    }
-  );
-
   //  Ord :: TypeClass
   var Ord = $.TypeClass(
     'sanctuary/Ord',
@@ -1096,26 +1087,6 @@
          [$Maybe(a), $.Function, b],
          Maybe$prototype$sequence);
 
-  //# Maybe#toBoolean :: Maybe a ~> () -> Boolean
-  //.
-  //. Returns `false` if `this` is Nothing; `true` if `this` is a Just.
-  //.
-  //. ```javascript
-  //. > S.Nothing.toBoolean()
-  //. false
-  //.
-  //. > S.Just(42).toBoolean()
-  //. true
-  //. ```
-  function Maybe$prototype$toBoolean(self) {
-    return self.isJust;
-  }
-  Maybe.prototype.toBoolean =
-  method('Maybe#toBoolean',
-         {},
-         [$Maybe(a), $.Boolean],
-         Maybe$prototype$toBoolean);
-
   //# Maybe#toString :: Maybe a ~> () -> String
   //.
   //. Returns the string representation of the Maybe.
@@ -1704,26 +1675,6 @@
          [$Either(a, b), $.Function, c],
          Either$prototype$sequence);
 
-  //# Either#toBoolean :: Either a b ~> () -> Boolean
-  //.
-  //. Returns `false` if `this` is a Left; `true` if `this` is a Right.
-  //.
-  //. ```javascript
-  //. > S.Left(42).toBoolean()
-  //. false
-  //.
-  //. > S.Right(42).toBoolean()
-  //. true
-  //. ```
-  function Either$prototype$toBoolean(self) {
-    return self.isRight;
-  }
-  Either.prototype.toBoolean =
-  method('Either#toBoolean',
-         {},
-         [$Either(a, b), $.Boolean],
-         Either$prototype$toBoolean);
-
   //# Either#toString :: Either a b ~> () -> String
   //.
   //. Returns the string representation of the Either.
@@ -2033,108 +1984,62 @@
   S.eitherToMaybe =
   def('eitherToMaybe', {}, [$Either(a, b), $Maybe(b)], eitherToMaybe);
 
-  //. ### Alternative
-
-  //  Alternative :: TypeClass
-  var Alternative = $.TypeClass(
-    'Alternative',
-    function(x) {
-      return R.contains(R.type(x), ['Array', 'Boolean']) ||
-             hasMethod('toBoolean')(x);
-    }
-  );
-
-  //  toBoolean :: Alternative a => a -> Boolean
-  var toBoolean = function(x) {
-    switch (R.type(x)) {
-      case 'Array':     return x.length > 0;
-      case 'Boolean':   return x.valueOf();
-      default:          return x.toBoolean();
-    }
-  };
-
-  //  empty :: Monoid a => a -> a
-  var empty = function(x) {
-    switch (R.type(x)) {
-      case 'Array':     return [];
-      case 'Boolean':   return false;
-      default:          return x.empty();
-    }
-  };
+  //. ### Logic
 
-  //# and :: Alternative a => a -> a -> a
+  //# and :: Boolean -> Boolean -> Boolean
   //.
-  //. Takes two values of the same type and returns the second value
-  //. if the first is "true"; the first value otherwise. An array is
-  //. considered "true" if its length is greater than zero. The Boolean
-  //. value `true` is also considered "true". Other types must provide
-  //. a `toBoolean` method.
+  //. Boolean "and".
   //.
   //. ```javascript
-  //. > S.and(S.Just(1), S.Just(2))
-  //. Just(2)
+  //. > S.and(false, false)
+  //. false
   //.
-  //. > S.and(S.Nothing, S.Just(3))
-  //. Nothing
+  //. > S.and(false, true)
+  //. false
+  //.
+  //. > S.and(true, false)
+  //. false
+  //.
+  //. > S.and(true, true)
+  //. true
   //. ```
   function and(x, y) {
-    return toBoolean(x) ? y : x;
+    return x.valueOf() && y.valueOf();
   }
-  S.and = def('and', {a: [Alternative]}, [a, a, a], and);
+  S.and = def('and', {}, [$.Boolean, $.Boolean, $.Boolean], and);
 
-  //# or :: Alternative a => a -> a -> a
+  //# or :: Boolean -> Boolean -> Boolean
   //.
-  //. Takes two values of the same type and returns the first value if it
-  //. is "true"; the second value otherwise. An array is considered "true"
-  //. if its length is greater than zero. The Boolean value `true` is also
-  //. considered "true". Other types must provide a `toBoolean` method.
+  //. Boolean "or".
   //.
   //. ```javascript
-  //. > S.or(S.Just(1), S.Just(2))
-  //. Just(1)
-  //.
-  //. > S.or(S.Nothing, S.Just(3))
-  //. Just(3)
-  //. ```
-  function or(x, y) {
-    return toBoolean(x) ? x : y;
-  }
-  S.or = def('or', {a: [Alternative]}, [a, a, a], or);
-
-  //# xor :: (Alternative a, Monoid a) => a -> a -> a
+  //. > S.or(false, false)
+  //. false
   //.
-  //. Takes two values of the same type and returns the "true" value
-  //. if one value is "true" and the other is "false"; otherwise it
-  //. returns the type's "false" value. An array is considered "true"
-  //. if its length is greater than zero. The Boolean value `true` is
-  //. also considered "true". Other types must provide `toBoolean` and
-  //. `empty` methods.
+  //. > S.or(false, true)
+  //. true
   //.
-  //. ```javascript
-  //. > S.xor(S.Nothing, S.Just(1))
-  //. Just(1)
+  //. > S.or(true, false)
+  //. true
   //.
-  //. > S.xor(S.Just(2), S.Just(3))
-  //. Nothing
+  //. > S.or(true, true)
+  //. true
   //. ```
-  function xor(x, y) {
-    return toBoolean(x) === toBoolean(y) ? empty(x) : or(x, y);
+  function or(x, y) {
+    return x.valueOf() || y.valueOf();
   }
-  S.xor = def('xor', {a: [Alternative, Monoid]}, [a, a, a], xor);
-
-  //. ### Logic
+  S.or = def('or', {}, [$.Boolean, $.Boolean, $.Boolean], or);
 
   //# not :: Boolean -> Boolean
   //.
-  //. Takes a Boolean and returns the negation of that value
-  //. (`false` for `true`; `true` for `false`).
+  //. Boolean "not".
   //.
   //. ```javascript
-  //. > S.not(true)
-  //. false
-  //.
   //. > S.not(false)
   //. true
+  //.
+  //. > S.not(true)
+  //. false
   //. ```
   function not(x) {
     return !x.valueOf();


Test patch:
diff --git a/test/Either/Left.js b/test/Either/Left.js
index 4f2b77b..15ab1cd 100644
--- a/test/Either/Left.js
+++ b/test/Either/Left.js
@@ -187,11 +187,6 @@ describe('Left', function() {
     eq(S.Left('abc').sequence(S.Maybe.of), S.Just(S.Left('abc')));
   });
 
-  it('provides a "toBoolean" method', function() {
-    eq(S.Left('abc').toBoolean.length, 0);
-    eq(S.Left('abc').toBoolean(), false);
-  });
-
   it('provides a "toString" method', function() {
     eq(S.Left('abc').toString.length, 0);
     eq(S.Left('abc').toString(), 'Left("abc")');
diff --git a/test/Either/Right.js b/test/Either/Right.js
index 2b39779..59f0140 100644
--- a/test/Either/Right.js
+++ b/test/Either/Right.js
@@ -187,11 +187,6 @@ describe('Right', function() {
     eq(S.Right(S.Just(42)).sequence(S.Maybe.of), S.Just(S.Right(42)));
   });
 
-  it('provides a "toBoolean" method', function() {
-    eq(S.Right(42).toBoolean.length, 0);
-    eq(S.Right(42).toBoolean(), true);
-  });
-
   it('provides a "toString" method', function() {
     eq(S.Right([1, 2, 3]).toString.length, 0);
     eq(S.Right([1, 2, 3]).toString(), 'Right([1, 2, 3])');
diff --git a/test/Maybe/Just.js b/test/Maybe/Just.js
index 6ef2089..f1006d5 100644
--- a/test/Maybe/Just.js
+++ b/test/Maybe/Just.js
@@ -215,11 +215,6 @@ describe('Just', function() {
     eq(S.Just(S.Right(42)).sequence(S.Either.of), S.Right(S.Just(42)));
   });
 
-  it('provides a "toBoolean" method', function() {
-    eq(S.Just(42).toBoolean.length, 0);
-    eq(S.Just(42).toBoolean(), true);
-  });
-
   it('provides a "toString" method', function() {
     eq(S.Just([1, 2, 3]).toString.length, 0);
     eq(S.Just([1, 2, 3]).toString(), 'Just([1, 2, 3])');
diff --git a/test/Maybe/Nothing.js b/test/Maybe/Nothing.js
index f71cea1..550fcec 100644
--- a/test/Maybe/Nothing.js
+++ b/test/Maybe/Nothing.js
@@ -178,11 +178,6 @@ describe('Nothing', function() {
     eq(S.Nothing.sequence(S.Either.of), S.Right(S.Nothing));
   });
 
-  it('provides a "toBoolean" method', function() {
-    eq(S.Nothing.toBoolean.length, 0);
-    eq(S.Nothing.toBoolean(), false);
-  });
-
   it('provides a "toString" method', function() {
     eq(S.Nothing.toString.length, 0);
     eq(S.Nothing.toString(), 'Nothing');
diff --git a/test/and.js b/test/and.js
index 8792892..b377988 100644
--- a/test/and.js
+++ b/test/and.js
@@ -1,13 +1,8 @@
 'use strict';
 
-var throws = require('assert').throws;
-
-var R = require('ramda');
-
 var S = require('..');
 
 var eq = require('./internal/eq');
-var errorEq = require('./internal/errorEq');
 
 
 describe('and', function() {
@@ -17,76 +12,15 @@ describe('and', function() {
     eq(S.and.length, 2);
   });
 
-  it('can be applied to Booleans', function() {
+  it('has && semantics', function() {
     eq(S.and(false, false), false);
     eq(S.and(false, true), false);
     eq(S.and(true, false), false);
     eq(S.and(true, true), true);
-  });
-
-  it('can be applied to arrays', function() {
-    eq(S.and([], []), []);
-    eq(S.and([], [42]), []);
-    eq(S.and([42], []), []);
-    eq(S.and([42], [43]), [43]);
-  });
-
-  it('can be applied to maybes', function() {
-    eq(S.and(S.Nothing, S.Nothing), S.Nothing);
-    eq(S.and(S.Nothing, S.Just(42)), S.Nothing);
-    eq(S.and(S.Just(42), S.Nothing), S.Nothing);
-    eq(S.and(S.Just(42), S.Just(43)), S.Just(43));
-  });
-
-  it('can be applied to eithers', function() {
-    eq(S.and(S.Left('foo'), S.Left('bar')), S.Left('foo'));
-    eq(S.and(S.Left('foo'), S.Right(42)), S.Left('foo'));
-    eq(S.and(S.Right(42), S.Left('foo')), S.Left('foo'));
-    eq(S.and(S.Right(42), S.Right(43)), S.Right(43));
-  });
-
-  it('throws if applied to values of different types', function() {
-    throws(function() { S.and([], false); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'and :: Alternative a => a -> a -> a\n' +
-                   '                        ^    ^\n' +
-                   '                        1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-
-    throws(function() { S.and(R.__, false)([]); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'and :: Alternative a => a -> a -> a\n' +
-                   '                        ^    ^\n' +
-                   '                        1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-  });
-
-  it('throws if applied to values without a "toBoolean" method', function() {
-    throws(function() { S.and(0, 1); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'and :: Alternative a => a -> a -> a\n' +
-                   '       ^^^^^^^^^^^^^    ^\n' +
-                   '                        1\n' +
-                   '\n' +
-                   '1)  0 :: Number, FiniteNumber, Integer, ValidNumber\n' +
-                   '\n' +
-                   '‘and’ requires ‘a’ to satisfy the Alternative type-class constraint; the value at position 1 does not.\n'));
+    eq(S.and(new Boolean(false), new Boolean(false)), false);
+    eq(S.and(new Boolean(false), new Boolean(true)), false);
+    eq(S.and(new Boolean(true), new Boolean(false)), false);
+    eq(S.and(new Boolean(true), new Boolean(true)), true);
   });
 
 });
diff --git a/test/or.js b/test/or.js
index 111e827..7177cad 100644
--- a/test/or.js
+++ b/test/or.js
@@ -1,13 +1,8 @@
 'use strict';
 
-var throws = require('assert').throws;
-
-var R = require('ramda');
-
 var S = require('..');
 
 var eq = require('./internal/eq');
-var errorEq = require('./internal/errorEq');
 
 
 describe('or', function() {
@@ -17,76 +12,15 @@ describe('or', function() {
     eq(S.or.length, 2);
   });
 
-  it('can be applied to Booleans', function() {
+  it('has || semantics', function() {
     eq(S.or(false, false), false);
     eq(S.or(false, true), true);
     eq(S.or(true, false), true);
     eq(S.or(true, true), true);
-  });
-
-  it('can be applied to arrays', function() {
-    eq(S.or([], []), []);
-    eq(S.or([], [42]), [42]);
-    eq(S.or([42], []), [42]);
-    eq(S.or([42], [43]), [42]);
-  });
-
-  it('can be applied to maybes', function() {
-    eq(S.or(S.Nothing, S.Nothing), S.Nothing);
-    eq(S.or(S.Nothing, S.Just(42)), S.Just(42));
-    eq(S.or(S.Just(42), S.Nothing), S.Just(42));
-    eq(S.or(S.Just(42), S.Just(43)), S.Just(42));
-  });
-
-  it('can be applied to eithers', function() {
-    eq(S.or(S.Left('foo'), S.Left('bar')), S.Left('bar'));
-    eq(S.or(S.Left('foo'), S.Right(42)), S.Right(42));
-    eq(S.or(S.Right(42), S.Left('foo')), S.Right(42));
-    eq(S.or(S.Right(42), S.Right(43)), S.Right(42));
-  });
-
-  it('throws if applied to values of different types', function() {
-    throws(function() { S.or([], false); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'or :: Alternative a => a -> a -> a\n' +
-                   '                       ^    ^\n' +
-                   '                       1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-
-    throws(function() { S.or(R.__, false)([]); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'or :: Alternative a => a -> a -> a\n' +
-                   '                       ^    ^\n' +
-                   '                       1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-  });
-
-  it('throws if applied to values without a "toBoolean" method', function() {
-    throws(function() { S.or(0, 1); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'or :: Alternative a => a -> a -> a\n' +
-                   '      ^^^^^^^^^^^^^    ^\n' +
-                   '                       1\n' +
-                   '\n' +
-                   '1)  0 :: Number, FiniteNumber, Integer, ValidNumber\n' +
-                   '\n' +
-                   '‘or’ requires ‘a’ to satisfy the Alternative type-class constraint; the value at position 1 does not.\n'));
+    eq(S.or(new Boolean(false), new Boolean(false)), false);
+    eq(S.or(new Boolean(false), new Boolean(true)), true);
+    eq(S.or(new Boolean(true), new Boolean(false)), true);
+    eq(S.or(new Boolean(true), new Boolean(true)), true);
   });
 
 });
diff --git a/test/xor.js b/test/xor.js
deleted file mode 100644
index b79b9d2..0000000
--- a/test/xor.js
+++ /dev/null
@@ -1,135 +0,0 @@
-'use strict';
-
-var throws = require('assert').throws;
-
-var R = require('ramda');
-
-var S = require('..');
-
-var eq = require('./internal/eq');
-var errorEq = require('./internal/errorEq');
-
-
-describe('xor', function() {
-
-  it('is a binary function', function() {
-    eq(typeof S.xor, 'function');
-    eq(S.xor.length, 2);
-  });
-
-  it('can be applied to Booleans', function() {
-    eq(S.xor(false, false), false);
-    eq(S.xor(false, true), true);
-    eq(S.xor(true, false), true);
-    eq(S.xor(true, true), false);
-  });
-
-  it('can be applied to arrays', function() {
-    eq(S.xor([], []), []);
-    eq(S.xor([], [42]), [42]);
-    eq(S.xor([42], []), [42]);
-    eq(S.xor([42], [43]), []);
-  });
-
-  it('can be applied to maybes', function() {
-    eq(S.xor(S.Nothing, S.Nothing), S.Nothing);
-    eq(S.xor(S.Nothing, S.Just(42)), S.Just(42));
-    eq(S.xor(S.Just(42), S.Nothing), S.Just(42));
-    eq(S.xor(S.Just(42), S.Just(43)), S.Nothing);
-  });
-
-  it('cannot be applied to eithers', function() {
-    throws(function() { S.xor(S.Left('foo'), S.Left('bar')); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                       ^^^^^^^^     ^\n' +
-                   '                                    1\n' +
-                   '\n' +
-                   '1)  Left("foo") :: Either String ???\n' +
-                   '\n' +
-                   '‘xor’ requires ‘a’ to satisfy the Monoid type-class constraint; the value at position 1 does not.\n'));
-
-    throws(function() { S.xor(S.Left('foo'), S.Right(42)); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                       ^^^^^^^^     ^\n' +
-                   '                                    1\n' +
-                   '\n' +
-                   '1)  Left("foo") :: Either String ???\n' +
-                   '\n' +
-                   '‘xor’ requires ‘a’ to satisfy the Monoid type-class constraint; the value at position 1 does not.\n'));
-
-    throws(function() { S.xor(S.Right(42), S.Left('foo')); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                       ^^^^^^^^     ^\n' +
-                   '                                    1\n' +
-                   '\n' +
-                   '1)  Right(42) :: Either ??? Number, Either ??? FiniteNumber, Either ??? NonZeroFiniteNumber, Either ??? Integer, Either ??? ValidNumber\n' +
-                   '\n' +
-                   '‘xor’ requires ‘a’ to satisfy the Monoid type-class constraint; the value at position 1 does not.\n'));
-
-    throws(function() { S.xor(S.Right(42), S.Right(43)); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                       ^^^^^^^^     ^\n' +
-                   '                                    1\n' +
-                   '\n' +
-                   '1)  Right(42) :: Either ??? Number, Either ??? FiniteNumber, Either ??? NonZeroFiniteNumber, Either ??? Integer, Either ??? ValidNumber\n' +
-                   '\n' +
-                   '‘xor’ requires ‘a’ to satisfy the Monoid type-class constraint; the value at position 1 does not.\n'));
-  });
-
-  it('throws if applied to values of different types', function() {
-    throws(function() { S.xor([], false); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                                    ^    ^\n' +
-                   '                                    1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-
-    throws(function() { S.xor(R.__, false)([]); },
-           errorEq(TypeError,
-                   'Type-variable constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '                                    ^    ^\n' +
-                   '                                    1    2\n' +
-                   '\n' +
-                   '1)  [] :: Array ???\n' +
-                   '\n' +
-                   '2)  false :: Boolean\n' +
-                   '\n' +
-                   'Since there is no type of which all the above values are members, the type-variable constraint has been violated.\n'));
-  });
-
-  it('throws if applied to values without a "toBoolean" method', function() {
-    throws(function() { S.xor(0, 1); },
-           errorEq(TypeError,
-                   'Type-class constraint violation\n' +
-                   '\n' +
-                   'xor :: (Alternative a, Monoid a) => a -> a -> a\n' +
-                   '        ^^^^^^^^^^^^^               ^\n' +
-                   '                                    1\n' +
-                   '\n' +
-                   '1)  0 :: Number, FiniteNumber, Integer, ValidNumber\n' +
-                   '\n' +
-                   '‘xor’ requires ‘a’ to satisfy the Alternative type-class constraint; the value at position 1 does not.\n'));
-  });
-
-});