001    package fj.pre;
002    
003    import fj.F;
004    import fj.F2;
005    import fj.P1;
006    import fj.P2;
007    import fj.P3;
008    import fj.P4;
009    import fj.P5;
010    import fj.P6;
011    import fj.P7;
012    import fj.P8;
013    import static fj.FW.$;
014    import static fj.Function.curry;
015    import fj.data.hlist.HList;
016    import fj.data.Array;
017    import fj.data.Either;
018    import fj.data.LazyString;
019    import fj.data.List;
020    import fj.data.NonEmptyList;
021    import fj.data.Option;
022    import fj.data.Set;
023    import fj.data.Stream;
024    import fj.data.Tree;
025    import fj.data.Validation;
026    import fj.data.vector.V2;
027    import fj.data.vector.V3;
028    import fj.data.vector.V4;
029    import fj.data.vector.V5;
030    import fj.data.vector.V6;
031    import fj.data.vector.V7;
032    import fj.data.vector.V8;
033    
034    import java.math.BigInteger;
035    import java.math.BigDecimal;
036    
037    /**
038     * Tests for equality between two objects.
039     *
040     * @version %build.number%<br>
041     *          <ul>
042     *          <li>$LastChangedRevision: 144 $</li>
043     *          <li>$LastChangedDate: 2009-05-27 01:24:17 +1000 (Wed, 27 May 2009) $</li>
044     *          </ul>
045     */
046    public final class Equal<A> {
047      private final F<A, F<A, Boolean>> f;
048    
049      private Equal(final F<A, F<A, Boolean>> f) {
050        this.f = f;
051      }
052    
053      /**
054       * Returns <code>true</code> if the two given arguments are equal, <code>false</code> otherwise.
055       *
056       * @param a1 An object to test for equality against another.
057       * @param a2 An object to test for equality against another.
058       * @return <code>true</code> if the two given arguments are equal, <code>false</code> otherwise.
059       */
060      public boolean eq(final A a1, final A a2) {
061        return f.f(a1).f(a2);
062      }
063    
064      /**
065       * First-class equality check.
066       *
067       * @return A function that returns <code>true</code> if the two given arguments are equal.
068       */
069      public F2<A, A, Boolean> eq() {
070        return new F2<A, A, Boolean>() {
071          public Boolean f(final A a, final A a1) {
072            return eq(a, a1);
073          }
074        };
075      }
076    
077      /**
078       * Partially applied equality check.
079       *
080       * @param a An object to test for equality against another.
081       * @return A function that returns <code>true</code> if the given argument equals the argument to this method.
082       */
083      public F<A, Boolean> eq(final A a) {
084        return new F<A, Boolean>() {
085          public Boolean f(final A a1) {
086            return eq(a, a1);
087          }
088        };
089      }
090    
091      /**
092       * Maps the given function across this equal as a contra-variant functor.
093       *
094       * @param f The function to map.
095       * @return A new equal.
096       */
097      public <B> Equal<B> comap(final F<B, A> f) {
098        return equal($(f).<Boolean>andThen_().o(this.f).o(f));
099      }
100    
101      /**
102       * Constructs an equal instance from the given function.
103       *
104       * @param f The function to construct the equal with.
105       * @return An equal instance from the given function.
106       */
107      public static <A> Equal<A> equal(final F<A, F<A, Boolean>> f) {
108        return new Equal<A>(f);
109      }
110    
111      /**
112       * Returns an equal instance that uses the {@link Object#equals(Object)} method to test for
113       * equality.
114       *
115       * @return An equal instance that uses the {@link Object#equals(Object)} method to test for
116       *         equality.
117       */
118      public static <A> Equal<A> anyEqual() {
119        return new Equal<A>(new F<A, F<A, Boolean>>() {
120          public F<A, Boolean> f(final A a1) {
121            return new F<A, Boolean>() {
122              public Boolean f(final A a2) {
123                return a1.equals(a2);
124              }
125            };
126          }
127        });
128      }
129    
130      /**
131       * An equal instance for the <code>boolean</code> type.
132       */
133      public static final Equal<Boolean> booleanEqual = anyEqual();
134    
135      /**
136       * An equal instance for the <code>byte</code> type.
137       */
138      public static final Equal<Byte> byteEqual = anyEqual();
139    
140      /**
141       * An equal instance for the <code>char</code> type.
142       */
143      public static final Equal<Character> charEqual = anyEqual();
144    
145      /**
146       * An equal instance for the <code>double</code> type.
147       */
148      public static final Equal<Double> doubleEqual = anyEqual();
149    
150      /**
151       * An equal instance for the <code>float</code> type.
152       */
153      public static final Equal<Float> floatEqual = anyEqual();
154    
155      /**
156       * An equal instance for the <code>int</code> type.
157       */
158      public static final Equal<Integer> intEqual = anyEqual();
159    
160      /**
161       * An equal instance for the <code>BigInteger</code> type.
162       */
163      public static final Equal<BigInteger> bigintEqual = anyEqual();
164    
165      /**
166       * An equal instance for the <code>BigDecimal</code> type.
167       */
168      public static final Equal<BigDecimal> bigdecimalEqual = anyEqual();
169    
170      /**
171       * An equal instance for the <code>long</code> type.
172       */
173      public static final Equal<Long> longEqual = anyEqual();
174    
175      /**
176       * An equal instance for the <code>short</code> type.
177       */
178      public static final Equal<Short> shortEqual = anyEqual();
179    
180      /**
181       * An equal instance for the {@link String} type.
182       */
183      public static final Equal<String> stringEqual = anyEqual();
184    
185      /**
186       * An equal instance for the {@link StringBuffer} type.
187       */
188      public static final Equal<StringBuffer> stringBufferEqual =
189          new Equal<StringBuffer>(new F<StringBuffer, F<StringBuffer, Boolean>>() {
190            public F<StringBuffer, Boolean> f(final StringBuffer sb1) {
191              return new F<StringBuffer, Boolean>() {
192                public Boolean f(final StringBuffer sb2) {
193                  if (sb1.length() == sb2.length()) {
194                    for (int i = 0; i < sb1.length(); i++)
195                      if (sb1.charAt(i) != sb2.charAt(i))
196                        return false;
197                    return true;
198                  } else
199                    return false;
200                }
201              };
202            }
203          });
204    
205      /**
206       * An equal instance for the {@link StringBuilder} type.
207       */
208      public static final Equal<StringBuilder> stringBuilderEqual =
209          new Equal<StringBuilder>(new F<StringBuilder, F<StringBuilder, Boolean>>() {
210            public F<StringBuilder, Boolean> f(final StringBuilder sb1) {
211              return new F<StringBuilder, Boolean>() {
212                public Boolean f(final StringBuilder sb2) {
213                  if (sb1.length() == sb2.length()) {
214                    for (int i = 0; i < sb1.length(); i++)
215                      if (sb1.charAt(i) != sb2.charAt(i))
216                        return false;
217                    return true;
218                  } else
219                    return false;
220                }
221              };
222            }
223          });
224    
225      /**
226       * An equal instance for the {@link Either} type.
227       *
228       * @param ea Equality across the left side of {@link Either}.
229       * @param eb Equality across the right side of {@link Either}.
230       * @return An equal instance for the {@link Either} type.
231       */
232      public static <A, B> Equal<Either<A, B>> eitherEqual(final Equal<A> ea, final Equal<B> eb) {
233        return new Equal<Either<A, B>>(new F<Either<A, B>, F<Either<A, B>, Boolean>>() {
234          public F<Either<A, B>, Boolean> f(final Either<A, B> e1) {
235            return new F<Either<A, B>, Boolean>() {
236              public Boolean f(final Either<A, B> e2) {
237                return e1.isLeft() && e2.isLeft() && ea.f.f(e1.left().value()).f(e2.left().value()) ||
238                       e1.isRight() && e2.isRight() && eb.f.f(e1.right().value()).f(e2.right().value());
239              }
240            };
241          }
242        });
243      }
244    
245      /**
246       * An equal instance for the {@link Validation} type.
247       *
248       * @param ea Equality across the failing side of {@link Validation}.
249       * @param eb Equality across the succeeding side of {@link Validation}.
250       * @return An equal instance for the {@link Validation} type.
251       */
252      public static <A, B> Equal<Validation<A, B>> validationEqual(final Equal<A> ea, final Equal<B> eb) {
253        return eitherEqual(ea, eb).comap(Validation.<A, B>either());
254      }
255    
256      /**
257       * An equal instance for the {@link List} type.
258       *
259       * @param ea Equality across the elements of the list.
260       * @return An equal instance for the {@link List} type.
261       */
262      public static <A> Equal<List<A>> listEqual(final Equal<A> ea) {
263        return new Equal<List<A>>(new F<List<A>, F<List<A>, Boolean>>() {
264          public F<List<A>, Boolean> f(final List<A> a1) {
265            return new F<List<A>, Boolean>() {
266              public Boolean f(final List<A> a2) {
267                List<A> x1 = a1;
268                List<A> x2 = a2;
269    
270                while (x1.isNotEmpty() && x2.isNotEmpty()) {
271                  if (!ea.eq(x1.head(), x2.head()))
272                    return false;
273    
274                  x1 = x1.tail();
275                  x2 = x2.tail();
276                }
277    
278                return x1.isEmpty() && x2.isEmpty();
279              }
280            };
281          }
282        });
283      }
284    
285      /**
286       * An equal instance for the {@link NonEmptyList} type.
287       *
288       * @param ea Equality across the elements of the non-empty list.
289       * @return An equal instance for the {@link NonEmptyList} type.
290       */
291      public static <A> Equal<NonEmptyList<A>> nonEmptyListEqual(final Equal<A> ea) {
292        return listEqual(ea).comap(NonEmptyList.<A>toList_());
293      }
294    
295      /**
296       * An equal instance for the {@link Option} type.
297       *
298       * @param ea Equality across the element of the option.
299       * @return An equal instance for the {@link Option} type.
300       */
301      public static <A> Equal<Option<A>> optionEqual(final Equal<A> ea) {
302        return new Equal<Option<A>>(new F<Option<A>, F<Option<A>, Boolean>>() {
303          public F<Option<A>, Boolean> f(final Option<A> o1) {
304            return new F<Option<A>, Boolean>() {
305              public Boolean f(final Option<A> o2) {
306                return o1.isNone() && o2.isNone() ||
307                       o1.isSome() && o2.isSome() && ea.f.f(o1.some()).f(o2.some());
308              }
309            };
310          }
311        });
312      }
313    
314      /**
315       * An equal instance for the {@link Stream} type.
316       *
317       * @param ea Equality across the elements of the stream.
318       * @return An equal instance for the {@link Stream} type.
319       */
320      public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) {
321        return new Equal<Stream<A>>(new F<Stream<A>, F<Stream<A>, Boolean>>() {
322          public F<Stream<A>, Boolean> f(final Stream<A> a1) {
323            return new F<Stream<A>, Boolean>() {
324              public Boolean f(final Stream<A> a2) {
325                Stream<A> x1 = a1;
326                Stream<A> x2 = a2;
327    
328                while (x1.isNotEmpty() && x2.isNotEmpty()) {
329                  if (!ea.eq(x1.head(), x2.head()))
330                    return false;
331    
332                  x1 = x1.tail()._1();
333                  x2 = x2.tail()._1();
334                }
335    
336                return x1.isEmpty() && x2.isEmpty();
337              }
338            };
339          }
340        });
341      }
342    
343      /**
344       * An equal instance for the {@link Array} type.
345       *
346       * @param ea Equality across the elements of the array.
347       * @return An equal instance for the {@link Array} type.
348       */
349      public static <A> Equal<Array<A>> arrayEqual(final Equal<A> ea) {
350        return new Equal<Array<A>>(new F<Array<A>, F<Array<A>, Boolean>>() {
351          public F<Array<A>, Boolean> f(final Array<A> a1) {
352            return new F<Array<A>, Boolean>() {
353              public Boolean f(final Array<A> a2) {
354                if (a1.length() == a2.length()) {
355                  for (int i = 0; i < a1.length(); i++) {
356                    if (!ea.eq(a1.get(i), a2.get(i)))
357                      return false;
358                  }
359                  return true;
360                } else
361                  return false;
362              }
363            };
364          }
365        });
366      }
367    
368      /**
369       * An equal instance for the {@link Tree} type.
370       *
371       * @param ea Equality across the elements of the tree.
372       * @return An equal instance for the {@link Tree} type.
373       */
374      public static <A> Equal<Tree<A>> treeEqual(final Equal<A> ea) {
375        return new Equal<Tree<A>>(curry(new F2<Tree<A>, Tree<A>, Boolean>() {
376          public Boolean f(final Tree<A> t1, final Tree<A> t2) {
377            return ea.eq(t1.root(), t2.root()) && p1Equal(streamEqual(treeEqual(ea))).eq(t2.subForest(), t1.subForest());
378          }
379        }));
380      }
381    
382      /**
383       * An equal instance for a product-1.
384       *
385       * @param ea Equality across the first element of the product.
386       * @return An equal instance for a product-1.
387       */
388      public static <A> Equal<P1<A>> p1Equal(final Equal<A> ea) {
389        return new Equal<P1<A>>(new F<P1<A>, F<P1<A>, Boolean>>() {
390          public F<P1<A>, Boolean> f(final P1<A> p1) {
391            return new F<P1<A>, Boolean>() {
392              public Boolean f(final P1<A> p2) {
393                return ea.eq(p1._1(), p2._1());
394              }
395            };
396          }
397        });
398      }
399    
400      /**
401       * An equal instance for a product-2.
402       *
403       * @param ea Equality across the first element of the product.
404       * @param eb Equality across the second element of the product.
405       * @return An equal instance for a product-2.
406       */
407      public static <A, B> Equal<P2<A, B>> p2Equal(final Equal<A> ea, final Equal<B> eb) {
408        return new Equal<P2<A, B>>(new F<P2<A, B>, F<P2<A, B>, Boolean>>() {
409          public F<P2<A, B>, Boolean> f(final P2<A, B> p1) {
410            return new F<P2<A, B>, Boolean>() {
411              public Boolean f(final P2<A, B> p2) {
412                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2());
413              }
414            };
415          }
416        });
417      }
418    
419      /**
420       * An equal instance for a product-3.
421       *
422       * @param ea Equality across the first element of the product.
423       * @param eb Equality across the second element of the product.
424       * @param ec Equality across the third element of the product.
425       * @return An equal instance for a product-3.
426       */
427      public static <A, B, C> Equal<P3<A, B, C>> p3Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec) {
428        return new Equal<P3<A, B, C>>(new F<P3<A, B, C>, F<P3<A, B, C>, Boolean>>() {
429          public F<P3<A, B, C>, Boolean> f(final P3<A, B, C> p1) {
430            return new F<P3<A, B, C>, Boolean>() {
431              public Boolean f(final P3<A, B, C> p2) {
432                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3());
433              }
434            };
435          }
436        });
437      }
438    
439      /**
440       * An equal instance for a product-4.
441       *
442       * @param ea Equality across the first element of the product.
443       * @param eb Equality across the second element of the product.
444       * @param ec Equality across the third element of the product.
445       * @param ed Equality across the fourth element of the product.
446       * @return An equal instance for a product-4.
447       */
448      public static <A, B, C, D> Equal<P4<A, B, C, D>> p4Equal(final Equal<A> ea, final Equal<B> eb, final Equal<C> ec,
449                                                               final Equal<D> ed) {
450        return new Equal<P4<A, B, C, D>>(new F<P4<A, B, C, D>, F<P4<A, B, C, D>, Boolean>>() {
451          public F<P4<A, B, C, D>, Boolean> f(final P4<A, B, C, D> p1) {
452            return new F<P4<A, B, C, D>, Boolean>() {
453              public Boolean f(final P4<A, B, C, D> p2) {
454                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
455                       ed.eq(p1._4(), p2._4());
456              }
457            };
458          }
459        });
460      }
461    
462      /**
463       * An equal instance for a product-5.
464       *
465       * @param ea Equality across the first element of the product.
466       * @param eb Equality across the second element of the product.
467       * @param ec Equality across the third element of the product.
468       * @param ed Equality across the fourth element of the product.
469       * @param ee Equality across the fifth element of the product.
470       * @return An equal instance for a product-5.
471       */
472      public static <A, B, C, D, E> Equal<P5<A, B, C, D, E>> p5Equal(final Equal<A> ea, final Equal<B> eb,
473                                                                     final Equal<C> ec, final Equal<D> ed,
474                                                                     final Equal<E> ee) {
475        return new Equal<P5<A, B, C, D, E>>(new F<P5<A, B, C, D, E>, F<P5<A, B, C, D, E>, Boolean>>() {
476          public F<P5<A, B, C, D, E>, Boolean> f(final P5<A, B, C, D, E> p1) {
477            return new F<P5<A, B, C, D, E>, Boolean>() {
478              public Boolean f(final P5<A, B, C, D, E> p2) {
479                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
480                       ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5());
481              }
482            };
483          }
484        });
485      }
486    
487      /**
488       * An equal instance for a product-6.
489       *
490       * @param ea Equality across the first element of the product.
491       * @param eb Equality across the second element of the product.
492       * @param ec Equality across the third element of the product.
493       * @param ed Equality across the fourth element of the product.
494       * @param ee Equality across the fifth element of the product.
495       * @param ef Equality across the sixth element of the product.
496       * @return An equal instance for a product-6.
497       */
498      public static <A, B, C, D, E, F$> Equal<P6<A, B, C, D, E, F$>> p6Equal(final Equal<A> ea, final Equal<B> eb,
499                                                                             final Equal<C> ec, final Equal<D> ed,
500                                                                             final Equal<E> ee, final Equal<F$> ef) {
501        return new Equal<P6<A, B, C, D, E, F$>>(new F<P6<A, B, C, D, E, F$>, F<P6<A, B, C, D, E, F$>, Boolean>>() {
502          public F<P6<A, B, C, D, E, F$>, Boolean> f(final P6<A, B, C, D, E, F$> p1) {
503            return new F<P6<A, B, C, D, E, F$>, Boolean>() {
504              public Boolean f(final P6<A, B, C, D, E, F$> p2) {
505                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
506                       ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6());
507              }
508            };
509          }
510        });
511      }
512    
513      /**
514       * An equal instance for a product-7.
515       *
516       * @param ea Equality across the first element of the product.
517       * @param eb Equality across the second element of the product.
518       * @param ec Equality across the third element of the product.
519       * @param ed Equality across the fourth element of the product.
520       * @param ee Equality across the fifth element of the product.
521       * @param ef Equality across the sixth element of the product.
522       * @param eg Equality across the seventh element of the product.
523       * @return An equal instance for a product-7.
524       */
525      public static <A, B, C, D, E, F$, G> Equal<P7<A, B, C, D, E, F$, G>> p7Equal(final Equal<A> ea, final Equal<B> eb,
526                                                                                   final Equal<C> ec, final Equal<D> ed,
527                                                                                   final Equal<E> ee, final Equal<F$> ef,
528                                                                                   final Equal<G> eg) {
529        return new Equal<P7<A, B, C, D, E, F$, G>>(new F<P7<A, B, C, D, E, F$, G>, F<P7<A, B, C, D, E, F$, G>, Boolean>>() {
530          public F<P7<A, B, C, D, E, F$, G>, Boolean> f(final P7<A, B, C, D, E, F$, G> p1) {
531            return new F<P7<A, B, C, D, E, F$, G>, Boolean>() {
532              public Boolean f(final P7<A, B, C, D, E, F$, G> p2) {
533                return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
534                       ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
535                       eg.eq(p1._7(), p2._7());
536              }
537            };
538          }
539        });
540      }
541    
542      /**
543       * An equal instance for a product-8.
544       *
545       * @param ea Equality across the first element of the product.
546       * @param eb Equality across the second element of the product.
547       * @param ec Equality across the third element of the product.
548       * @param ed Equality across the fourth element of the product.
549       * @param ee Equality across the fifth element of the product.
550       * @param ef Equality across the sixth element of the product.
551       * @param eg Equality across the seventh element of the product.
552       * @param eh Equality across the eighth element of the product.
553       * @return An equal instance for a product-8.
554       */
555      public static <A, B, C, D, E, F$, G, H> Equal<P8<A, B, C, D, E, F$, G, H>> p8Equal(final Equal<A> ea,
556                                                                                         final Equal<B> eb,
557                                                                                         final Equal<C> ec,
558                                                                                         final Equal<D> ed,
559                                                                                         final Equal<E> ee,
560                                                                                         final Equal<F$> ef,
561                                                                                         final Equal<G> eg,
562                                                                                         final Equal<H> eh) {
563        return new Equal<P8<A, B, C, D, E, F$, G, H>>(
564            new F<P8<A, B, C, D, E, F$, G, H>, F<P8<A, B, C, D, E, F$, G, H>, Boolean>>() {
565              public F<P8<A, B, C, D, E, F$, G, H>, Boolean> f(final P8<A, B, C, D, E, F$, G, H> p1) {
566                return new F<P8<A, B, C, D, E, F$, G, H>, Boolean>() {
567                  public Boolean f(final P8<A, B, C, D, E, F$, G, H> p2) {
568                    return ea.eq(p1._1(), p2._1()) && eb.eq(p1._2(), p2._2()) && ec.eq(p1._3(), p2._3()) &&
569                           ed.eq(p1._4(), p2._4()) && ee.eq(p1._5(), p2._5()) && ef.eq(p1._6(), p2._6()) &&
570                           eg.eq(p1._7(), p2._7()) && eh.eq(p1._8(), p2._8());
571                  }
572                };
573              }
574            });
575      }
576    
577      /**
578       * An equal instance for a vector-2.
579       *
580       * @param ea Equality across the elements of the vector.
581       * @return An equal instance for a vector-2.
582       */
583      public static <A> Equal<V2<A>> v2Equal(final Equal<A> ea) {
584        return streamEqual(ea).comap(V2.<A>toStream_());
585      }
586    
587      /**
588       * An equal instance for a vector-3.
589       *
590       * @param ea Equality across the elements of the vector.
591       * @return An equal instance for a vector-3.
592       */
593      public static <A> Equal<V3<A>> v3Equal(final Equal<A> ea) {
594        return streamEqual(ea).comap(V3.<A>toStream_());
595      }
596    
597      /**
598       * An equal instance for a vector-4.
599       *
600       * @param ea Equality across the elements of the vector.
601       * @return An equal instance for a vector-4.
602       */
603      public static <A> Equal<V4<A>> v4Equal(final Equal<A> ea) {
604        return streamEqual(ea).comap(V4.<A>toStream_());
605      }
606    
607      /**
608       * An equal instance for a vector-5.
609       *
610       * @param ea Equality across the elements of the vector.
611       * @return An equal instance for a vector-5.
612       */
613      public static <A> Equal<V5<A>> v5Equal(final Equal<A> ea) {
614        return streamEqual(ea).comap(V5.<A>toStream_());
615      }
616    
617      /**
618       * An equal instance for a vector-6.
619       *
620       * @param ea Equality across the elements of the vector.
621       * @return An equal instance for a vector-6.
622       */
623      public static <A> Equal<V6<A>> v6Equal(final Equal<A> ea) {
624        return streamEqual(ea).comap(V6.<A>toStream_());
625      }
626    
627      /**
628       * An equal instance for a vector-7.
629       *
630       * @param ea Equality across the elements of the vector.
631       * @return An equal instance for a vector-7.
632       */
633      public static <A> Equal<V7<A>> v7Equal(final Equal<A> ea) {
634        return streamEqual(ea).comap(V7.<A>toStream_());
635      }
636    
637      /**
638       * An equal instance for a vector-8.
639       *
640       * @param ea Equality across the elements of the vector.
641       * @return An equal instance for a vector-8.
642       */
643      public static <A> Equal<V8<A>> v8Equal(final Equal<A> ea) {
644        return streamEqual(ea).comap(V8.<A>toStream_());
645      }
646    
647      /**
648       * An equal instance for lazy strings.
649       */
650      public static final Equal<LazyString> eq = streamEqual(charEqual).comap(LazyString.toStream);
651    
652      /**
653       * An equal instance for the empty heterogeneous list.
654       */
655      public static final Equal<HList.HNil> hListEqual = anyEqual();
656    
657      /**
658       * An equal instance for heterogeneous lists.
659       *
660       * @param e Equality for the first element of the list.
661       * @param l Equality for the rest of the list.
662       * @return an equal instance for a heterogeneous list.
663       */
664      public static <E, L extends HList<L>> Equal<HList.HCons<E, L>> hListEqual(final Equal<E> e, final Equal<L> l) {
665        return equal(curry(new F2<HList.HCons<E, L>, HList.HCons<E, L>, Boolean>() {
666          public Boolean f(final HList.HCons<E, L> c1, final HList.HCons<E, L> c2) {
667            return e.eq(c1.head(), c2.head()) && l.eq(c1.tail(), c2.tail());
668          }
669        }));
670      }
671    
672      /**
673       * Equal instance for sets.
674       *
675       * @param e Equality for the set elements.
676       * @return An equal instance for sets.
677       */
678      public static <A> Equal<Set<A>> setEqual(final Equal<A> e) {
679        return equal(curry(new F2<Set<A>, Set<A>, Boolean>() {
680          public Boolean f(final Set<A> a, final Set<A> b) {
681            return streamEqual(e).eq(a.toStream(), b.toStream());
682          }
683        }));
684      }
685    }