Skip to content

Commit

Permalink
Merge pull request #154 from sanctuary-js/avaq/structural-equality
Browse files Browse the repository at this point in the history
Update the equals function to fall back to structural equality
  • Loading branch information
Avaq authored Jun 19, 2021
2 parents 72bbd79 + 4892eda commit 9e278b6
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
26 changes: 18 additions & 8 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -1113,12 +1113,20 @@

//# equals :: (a, b) -> Boolean
//.
//. Returns `true` if its arguments are of the same type and equal according
//. to the type's [`fantasy-land/equals`][] method; `false` otherwise.
//. Returns `true` if its arguments are equal; `false` otherwise.
//.
//. `fantasy-land/equals` implementations are provided for the following
//. built-in types: Null, Undefined, Boolean, Number, Date, RegExp, String,
//. Array, Arguments, Error, Object, and Function.
//. Specifically:
//.
//. - Arguments with different [type identities][] are unequal.
//.
//. - If the first argument has a [`fantasy-land/equals`][] method,
//. that method is invoked to determine whether the arguments are
//. equal (`fantasy-land/equals` implementations are provided for the
//. following built-in types: Null, Undefined, Boolean, Number, Date,
//. RegExp, String, Array, Arguments, Error, Object, and Function).
//.
//. - Otherwise, the arguments are equal if their
//. [entries][`Object.entries`] are equal (according to this algorithm).
//.
//. The algorithm supports circular data structures. Two arrays are equal
//. if they have the same index paths and for each path have equal values.
Expand Down Expand Up @@ -1154,9 +1162,9 @@

$pairs.push ([x, y]);
try {
return Z.Setoid.test (x) &&
Z.Setoid.test (y) &&
Z.Setoid.methods.equals (x) (y);
return Z.Setoid.test (x) ?
Z.Setoid.methods.equals (x) (y) :
Object$prototype$equals.call (x, y);
} finally {
$pairs.pop ();
}
Expand Down Expand Up @@ -2253,6 +2261,7 @@
//. [Semigroupoid]: v:fantasyland/fantasy-land#semigroupoid
//. [Setoid]: v:fantasyland/fantasy-land#setoid
//. [Traversable]: v:fantasyland/fantasy-land#traversable
//. [`Object.entries`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries
//. [`fantasy-land/alt`]: v:fantasyland/fantasy-land#alt-method
//. [`fantasy-land/ap`]: v:fantasyland/fantasy-land#ap-method
//. [`fantasy-land/bimap`]: v:fantasyland/fantasy-land#bimap-method
Expand All @@ -2276,4 +2285,5 @@
//. [`fantasy-land/traverse`]: v:fantasyland/fantasy-land#traverse-method
//. [`fantasy-land/zero`]: v:fantasyland/fantasy-land#zero-method
//. [stable sort]: https://en.wikipedia.org/wiki/Sorting_algorithm#Stability
//. [type identities]: v:sanctuary-js/sanctuary-type-identifiers
//. [type-classes]: https://github.com/sanctuary-js/sanctuary-def#type-classes
31 changes: 30 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,33 @@ test ('Contravariant', () => {
});

test ('equals', () => {
const {nestedSetoidArb} = jsc.letrec (tie => ({
builtinSetoidArb: jsc.record ({
value: tie ('nestedSetoidArb'),
}),
noSetoidArb: jsc.record ({
'value': tie ('nestedSetoidArb'),
'@@type': jsc.constant ('sanctuary-type-classes/NoSetoid@1'),
'@@show': jsc.constant (function() { return `NoSetoid (${show (this.value)})`; }),
}),
customSetoidArb: jsc.record ({
'value': tie ('nestedSetoidArb'),
'@@type': jsc.constant ('sanctuary-type-classes/CustomSetoid@1'),
'@@show': jsc.constant (function() { return `CustomSetoid (${show (this.value)})`; }),
'fantasy-land/equals': jsc.constant (function(other) {
return Z.equals (this.value, other.value);
}),
}),
nestedSetoidArb: jsc.oneof ([
tie ('builtinSetoidArb'),
tie ('noSetoidArb'),
tie ('customSetoidArb'),
jsc.nat,
]),
}));

nestedSetoidArb.show = show;

eq (Z.equals.length, 2);

eq (Z.equals (null, null), true);
Expand Down Expand Up @@ -673,7 +700,7 @@ test ('equals', () => {
eq (Z.equals (Math.sin, Math.cos), false);
eq (Z.equals (Identity (Identity (Identity (0))), Identity (Identity (Identity (0)))), true);
eq (Z.equals (Identity (Identity (Identity (0))), Identity (Identity (Identity (1)))), false);
eq (Z.equals (Useless, Useless), false);
eq (Z.equals (Useless, Useless), true);
eq (Z.equals (Array.prototype, Array.prototype), true);
eq (Z.equals (Nothing.constructor, Maybe), true);
eq (Z.equals ((Just (0)).constructor, Maybe), true);
Expand All @@ -686,6 +713,8 @@ test ('equals', () => {
eq (Z.equals ($0, $0), true);
eq (Z.equals ($0, $1), false);
eq (Z.equals ($1, $0), false);

jsc.assert (jsc.forall (nestedSetoidArb, x => Z.equals (x, x)));
});

test ('lt', () => {
Expand Down

0 comments on commit 9e278b6

Please sign in to comment.