001    package fj.data;
002    
003    import fj.Effect;
004    import fj.F;
005    import fj.F2;
006    import fj.P;
007    import fj.P1;
008    import fj.P2;
009    import fj.Unit;
010    import static fj.Function.*;
011    import static fj.P.p;
012    import static fj.P.p2;
013    import static fj.Unit.unit;
014    import static fj.data.List.iterableList;
015    import static fj.data.Option.none;
016    import static fj.data.Option.some;
017    
018    import static java.lang.Math.min;
019    import static java.lang.System.arraycopy;
020    import java.util.AbstractCollection;
021    import java.util.Arrays;
022    import java.util.Collection;
023    import java.util.Iterator;
024    import java.util.NoSuchElementException;
025    
026    /**
027     * Provides an interface to arrays.
028     *
029     * @version %build.number%<br>
030     *          <ul>
031     *          <li>$LastChangedRevision: 303 $</li>
032     *          <li>$LastChangedDate: 2010-01-20 14:16:55 +1000 (Wed, 20 Jan 2010) $</li>
033     *          </ul>
034     */
035    public final class Array<A> implements Iterable<A> {
036      private final Object[] a;
037    
038      @SuppressWarnings({"AssignmentToCollectionOrArrayFieldFromParameter"})
039      private Array(final Object[] a) {
040        this.a = a;
041      }
042    
043      /**
044       * Returns an iterator for this array. This method exists to permit the use in a <code>for</code>-each loop.
045       *
046       * @return A iterator for this array.
047       */
048      public Iterator<A> iterator() {
049        return toCollection().iterator();
050      }
051    
052      /**
053       * Returns the element at the given index if it exists, fails otherwise.
054       *
055       * @param index The index at which to get the element to return.
056       * @return The element at the given index if it exists, fails otherwise.
057       */
058      @SuppressWarnings("unchecked")
059      public A get(final int index) {
060        return (A) a[index];
061      }
062    
063      /**
064       * Sets the element at the given index to the given value.
065       *
066       * @param index The index at which to set the given value.
067       * @param a     The value to set at the given index.
068       * @return The unit value.
069       */
070      public Unit set(final int index, final A a) {
071        this.a[index] = a;
072        return unit();
073      }
074    
075      /**
076       * Returns the length of this array.
077       *
078       * @return The length of this array.
079       */
080      public int length() {
081        return a.length;
082      }
083    
084      public ImmutableProjection<A> immutable() {
085        return new ImmutableProjection<A>(this);
086      }
087    
088      /**
089       * Returns <code>true</code> is this array is empty, <code>false</code> otherwise.
090       *
091       * @return <code>true</code> is this array is empty, <code>false</code> otherwise.
092       */
093      public boolean isEmpty() {
094        return a.length == 0;
095      }
096    
097      /**
098       * Returns <code>false</code> is this array is empty, <code>true</code> otherwise.
099       *
100       * @return <code>false</code> is this array is empty, <code>true</code> otherwise.
101       */
102      public boolean isNotEmpty() {
103        return a.length != 0;
104      }
105    
106      /**
107       * Returns a copy of the underlying primitive array.
108       *
109       * @param c A class for the returned array.
110       * @return A copy of the underlying primitive array.
111       */
112      public A[] array(final Class<A[]> c) {
113        return Arrays.copyOf(a, a.length, c);
114      }
115    
116      /**
117       * Returns a copy of the underlying primitive array.
118       *
119       * @return A copy of the underlying primitive array;
120       */
121      public Object[] array() {
122        return Arrays.copyOf(a, a.length);
123      }
124    
125      /**
126       * Returns an option projection of this array; <code>None</code> if empty, or the first element in
127       * <code>Some</code>.
128       *
129       * @return An option projection of this array.
130       */
131      @SuppressWarnings("unchecked")
132      public Option<A> toOption() {
133        return a.length == 0 ? Option.<A>none() : some((A) a[0]);
134      }
135    
136      /**
137       * Returns an either projection of this array; the given argument in <code>Left</code> if empty,
138       * or the first element in <code>Right</code>.
139       *
140       * @param x The value to return in left if this array is empty.
141       * @return An either projection of this array.
142       */
143      @SuppressWarnings("unchecked")
144      public <X> Either<X, A> toEither(final P1<X> x) {
145        return a.length == 0 ? Either.<X, A>left(x._1()) : Either.<X, A>right((A) a[0]);
146      }
147    
148      /**
149       * Returns a list projection of this array.
150       *
151       * @return A list projection of this array.
152       */
153      @SuppressWarnings("unchecked")
154      public List<A> toList() {
155        List<A> x = List.nil();
156    
157        for (int i = a.length - 1; i >= 0; i--) {
158          x = x.cons((A) a[i]);
159        }
160    
161        return x;
162      }
163    
164      /**
165       * Returns a stream projection of this array.
166       *
167       * @return A stream projection of this array.
168       */
169      @SuppressWarnings("unchecked")
170      public Stream<A> toStream() {
171        return Stream.unfold(new F<Integer, Option<P2<A, Integer>>>() {
172          public Option<P2<A, Integer>> f(final Integer o) {
173            return a.length > o ? some(p((A) a[o], o + 1))
174                                : Option.<P2<A, Integer>>none();
175          }
176        }, 0);
177      }
178    
179      /**
180       * Maps the given function across this array.
181       *
182       * @param f The function to map across this array.
183       * @return A new array after the given function has been applied to each element.
184       */
185      @SuppressWarnings({"unchecked"})
186      public <B> Array<B> map(final F<A, B> f) {
187        final Object[] bs = new Object[a.length];
188    
189        for (int i = 0; i < a.length; i++) {
190          bs[i] = f.f((A) a[i]);
191        }
192    
193        return new Array<B>(bs);
194      }
195    
196      /**
197       * Filters elements from this array by returning only elements which produce <code>true</code>
198       * when the given function is applied to them.
199       *
200       * @param f The predicate function to filter on.
201       * @return A new array whose elements all match the given predicate.
202       */
203      @SuppressWarnings("unchecked")
204      public Array<A> filter(final F<A, Boolean> f) {
205        List<A> x = List.nil();
206    
207        for (int i = a.length - 1; i >= 0; i--) {
208          if (f.f((A) a[i]))
209            x = x.cons((A) a[i]);
210        }
211    
212        return x.toArray();
213      }
214    
215      /**
216       * Performs a side-effect for each element of this array.
217       *
218       * @param f The side-effect to perform for the given element.
219       * @return The unit value.
220       */
221      @SuppressWarnings("unchecked")
222      public Unit foreach(final F<A, Unit> f) {
223        for (final Object x : a) {
224          f.f((A) x);
225        }
226    
227        return unit();
228      }
229    
230      /**
231       * Performs a side-effect for each element of this array.
232       *
233       * @param f The side-effect to perform for the given element.
234       */
235      @SuppressWarnings("unchecked")
236      public void foreach(final Effect<A> f) {
237        for (final Object x : a) {
238          f.e((A) x);
239        }
240      }
241    
242      /**
243       * Performs a right-fold reduction across this array. This function runs in constant stack space.
244       *
245       * @param f The function to apply on each element of the array.
246       * @param b The beginning value to start the application from.
247       * @return The final result after the right-fold reduction.
248       */
249      @SuppressWarnings("unchecked")
250      public <B> B foldRight(final F<A, F<B, B>> f, final B b) {
251        B x = b;
252    
253        for (int i = a.length - 1; i >= 0; i--)
254          x = f.f((A) a[i]).f(x);
255    
256        return x;
257      }
258    
259      /**
260       * Performs a right-fold reduction across this array. This function runs in constant stack space.
261       *
262       * @param f The function to apply on each element of the array.
263       * @param b The beginning value to start the application from.
264       * @return The final result after the right-fold reduction.
265       */
266      public <B> B foldRight(final F2<A, B, B> f, final B b) {
267        return foldRight(curry(f), b);
268      }
269    
270      /**
271       * Performs a left-fold reduction across this array. This function runs in constant space.
272       *
273       * @param f The function to apply on each element of the array.
274       * @param b The beginning value to start the application from.
275       * @return The final result after the left-fold reduction.
276       */
277      @SuppressWarnings("unchecked")
278      public <B> B foldLeft(final F<B, F<A, B>> f, final B b) {
279        B x = b;
280    
281        for (final Object aa : a)
282          x = f.f(x).f((A) aa);
283    
284        return x;
285      }
286    
287      /**
288       * Performs a left-fold reduction across this array. This function runs in constant space.
289       *
290       * @param f The function to apply on each element of the array.
291       * @param b The beginning value to start the application from.
292       * @return The final result after the left-fold reduction.
293       */
294      public <B> B foldLeft(final F2<B, A, B> f, final B b) {
295        return foldLeft(curry(f), b);
296      }
297    
298      /**
299       * Binds the given function across each element of this array with a final join.
300       *
301       * @param f The function to apply to each element of this array.
302       * @return A new array after performing the map, then final join.
303       */
304      @SuppressWarnings({"unchecked"})
305      public <B> Array<B> bind(final F<A, Array<B>> f) {
306        List<Array<B>> x = List.nil();
307        int len = 0;
308    
309        for (int i = a.length - 1; i >= 0; i--) {
310          final Array<B> bs = f.f((A) a[i]);
311          len = len + bs.length();
312          x = x.cons(bs);
313        }
314    
315        final Object[] bs = new Object[len];
316    
317        x.foreach(new F<Array<B>, Unit>() {
318          private int i;
319    
320          public Unit f(final Array<B> x) {
321            arraycopy(x.a, 0, bs, i, x.a.length);
322            i = i + x.a.length;
323            return unit();
324          }
325        });
326    
327        return new Array<B>(bs);
328      }
329    
330      /**
331       * Performs a bind across each array element, but ignores the element value each time.
332       *
333       * @param bs The array to apply in the final join.
334       * @return A new array after the final join.
335       */
336      public <B> Array<B> sequence(final Array<B> bs) {
337        final F<A, Array<B>> c = constant(bs);
338        return bind(c);
339      }
340    
341      /**
342       * Binds the given function across each element of this array and the given array with a final
343       * join.
344       *
345       * @param sb A given array to bind the given function with.
346       * @param f  The function to apply to each element of this array and the given array.
347       * @return A new array after performing the map, then final join.
348       */
349      public <B, C> Array<C> bind(final Array<B> sb, final F<A, F<B, C>> f) {
350        return sb.apply(map(f));
351      }
352    
353      /**
354       * Binds the given function across each element of this array and the given array with a final
355       * join.
356       *
357       * @param sb A given array to bind the given function with.
358       * @param f  The function to apply to each element of this array and the given array.
359       * @return A new array after performing the map, then final join.
360       */
361      public <B, C> Array<C> bind(final Array<B> sb, final F2<A, B, C> f) {
362        return bind(sb, curry(f));
363      }
364    
365      /**
366       * Performs function application within an array (applicative functor pattern).
367       *
368       * @param lf The array of functions to apply.
369       * @return A new array after applying the given array of functions through this array.
370       */
371      public <B> Array<B> apply(final Array<F<A, B>> lf) {
372        return lf.bind(new F<F<A, B>, Array<B>>() {
373          public Array<B> f(final F<A, B> f) {
374            return map(new F<A, B>() {
375              public B f(final A a) {
376                return f.f(a);
377              }
378            });
379          }
380        });
381      }
382    
383      /**
384       * Reverse this array in constant stack space.
385       *
386       * @return A new array that is the reverse of this one.
387       */
388      public Array<A> reverse() {
389        final Object[] x = new Object[a.length];
390    
391        for (int i = 0; i < a.length; i++) {
392          x[a.length - 1 - i] = a[i];
393        }
394    
395        return new Array<A>(x);
396      }
397    
398      /**
399       * Appends the given array to this array.
400       *
401       * @param aas The array to append to this one.
402       * @return A new array that has appended the given array.
403       */
404      public Array<A> append(final Array<A> aas) {
405        final Object[] x = new Object[a.length + aas.a.length];
406    
407        arraycopy(a, 0, x, 0, a.length);
408        arraycopy(aas.a, 0, x, a.length, aas.a.length);
409    
410        return new Array<A>(x);
411      }
412    
413      /**
414       * Returns an empty array.
415       *
416       * @return An empty array.
417       */
418      public static <A> Array<A> empty() {
419        return new Array<A>(new Object[0]);
420      }
421    
422      /**
423       * Constructs an array from the given elements.
424       *
425       * @param a The elements to construct the array with.
426       * @return A new array of the given elements.
427       */
428      public static <A> Array<A> array(final A... a) {
429        return new Array<A>(a);
430      }
431    
432      /**
433       * Unsafe package-private constructor. The elements of the given array must be assignable to the given type.
434       *
435       * @param a An array with elements of the given type.
436       * @return A wrapped array.
437       */
438      static <A> Array<A> mkArray(final Object[] a) {
439        return new Array<A>(a);
440      }
441    
442      /**
443       * Constructs a singleton array.
444       *
445       * @param a The element to put in the array.
446       * @return An array with the given single element.
447       */
448      public static <A> Array<A> single(final A a) {
449        return new Array<A>(new Object[]{a});
450      }
451    
452      /**
453       * First-class wrapper function for arrays.
454       *
455       * @return A function that wraps a given array.
456       */
457      public static <A> F<A[], Array<A>> wrap() {
458        return new F<A[], Array<A>>() {
459          public Array<A> f(final A[] as) {
460            return array(as);
461          }
462        };
463      }
464    
465      /**
466       * First-class map function for Arrays.
467       *
468       * @return A function that maps a given function across a given array.
469       */
470      public static <A, B> F<F<A, B>, F<Array<A>, Array<B>>> map() {
471        return curry(new F2<F<A, B>, Array<A>, Array<B>>() {
472          public Array<B> f(final F<A, B> abf, final Array<A> array) {
473            return array.map(abf);
474          }
475        });
476      }
477    
478      /**
479       * Joins the given array of arrays using a bind operation.
480       *
481       * @param o The array of arrays to join.
482       * @return A new array that is the join of the given arrays.
483       */
484      public static <A> Array<A> join(final Array<Array<A>> o) {
485        final F<Array<A>, Array<A>> id = identity();
486        return o.bind(id);
487      }
488    
489      /**
490       * A first-class version of join
491       *
492       * @return A function that joins a array of arrays using a bind operation.
493       */
494      public static <A> F<Array<Array<A>>, Array<A>> join() {
495        return new F<Array<Array<A>>, Array<A>>() {
496          public Array<A> f(final Array<Array<A>> as) {
497            return join(as);
498          }
499        };
500      }
501    
502      /**
503       * Returns <code>true</code> if the predicate holds for all of the elements of this array,
504       * <code>false</code> otherwise (<code>true</code> for the empty array).
505       *
506       * @param f the predicate function to test on each element of this array.
507       * @return <code>true</code> if the predicate holds for all of the elements of this array,
508       *         <code>false</code> otherwise.
509       */
510      @SuppressWarnings("unchecked")
511      public boolean forall(final F<A, Boolean> f) {
512        for (final Object x : a)
513          if (!f.f((A) x))
514            return false;
515    
516        return true;
517      }
518    
519      /**
520       * Returns <code>true</code> if the predicate holds for at least one of the elements of this
521       * array, <code>false</code> otherwise (<code>false</code> for the empty array).
522       *
523       * @param f the predicate function to test on the elements of this array.
524       * @return <code>true</code> if the predicate holds for at least one of the elements of this
525       *         array.
526       */
527      @SuppressWarnings("unchecked")
528      public boolean exists(final F<A, Boolean> f) {
529        for (final Object x : a)
530          if (f.f((A) x))
531            return true;
532    
533        return false;
534      }
535    
536      /**
537       * Finds the first occurrence of an element that matches the given predicate or no value if no
538       * elements match.
539       *
540       * @param f The predicate function to test on elements of this array.
541       * @return The first occurrence of an element that matches the given predicate or no value if no
542       *         elements match.
543       */
544      @SuppressWarnings("unchecked")
545      public Option<A> find(final F<A, Boolean> f) {
546        for (final Object x : a)
547          if (f.f((A) x))
548            return some((A) x);
549    
550        return none();
551      }
552    
553      /**
554       * Returns an array of integers from the given <code>from</code> value (inclusive) to the given
555       * <code>to</code> value (exclusive).
556       *
557       * @param from The minimum value for the array (inclusive).
558       * @param to   The maximum value for the array (exclusive).
559       * @return An array of integers from the given <code>from</code> value (inclusive) to the given
560       *         <code>to</code> value (exclusive).
561       */
562      public static Array<Integer> range(final int from, final int to) {
563        if (from >= to)
564          return Array.empty();
565        else {
566          final Array<Integer> a = new Array<Integer>(new Integer[to - from]);
567    
568          for (int i = from; i < to; i++)
569            a.set(i - from, i);
570    
571          return a;
572        }
573      }
574    
575      /**
576       * Zips this array with the given array using the given function to produce a new array. If this
577       * array and the given array have different lengths, then the longer array is normalised so this
578       * function never fails.
579       *
580       * @param bs The array to zip this array with.
581       * @param f  The function to zip this array and the given array with.
582       * @return A new array with a length the same as the shortest of this array and the given array.
583       */
584      public <B, C> Array<C> zipWith(final Array<B> bs, final F<A, F<B, C>> f) {
585        final int len = min(a.length, bs.length());
586        final Array<C> x = new Array<C>(new Object[len]);
587    
588        for (int i = 0; i < len; i++) {
589          x.set(i, f.f(get(i)).f(bs.get(i)));
590        }
591    
592        return x;
593      }
594    
595      /**
596       * Zips this array with the given array using the given function to produce a new array. If this
597       * array and the given array have different lengths, then the longer array is normalised so this
598       * function never fails.
599       *
600       * @param bs The array to zip this array with.
601       * @param f  The function to zip this array and the given array with.
602       * @return A new array with a length the same as the shortest of this array and the given array.
603       */
604      public <B, C> Array<C> zipWith(final Array<B> bs, final F2<A, B, C> f) {
605        return zipWith(bs, curry(f));
606      }
607    
608      /**
609       * Zips this array with the given array to produce an array of pairs. If this array and the given
610       * array have different lengths, then the longer array is normalised so this function never fails.
611       *
612       * @param bs The array to zip this array with.
613       * @return A new array with a length the same as the shortest of this array and the given array.
614       */
615      public <B> Array<P2<A, B>> zip(final Array<B> bs) {
616        final F<A, F<B, P2<A, B>>> __2 = p2();
617        return zipWith(bs, __2);
618      }
619    
620      /**
621       * Zips this array with the index of its element as a pair.
622       *
623       * @return A new array with the same length as this array.
624       */
625      public Array<P2<A, Integer>> zipIndex() {
626        return zipWith(range(0, length()), new F<A, F<Integer, P2<A, Integer>>>() {
627          public F<Integer, P2<A, Integer>> f(final A a) {
628            return new F<Integer, P2<A, Integer>>() {
629              public P2<A, Integer> f(final Integer i) {
630                return p(a, i);
631              }
632            };
633          }
634        });
635      }
636    
637      /**
638       * Projects an immutable collection of this array.
639       *
640       * @return An immutable collection of this array.
641       */
642      @SuppressWarnings("unchecked")
643      public Collection<A> toCollection() {
644        return new AbstractCollection<A>() {
645          public Iterator<A> iterator() {
646            return new Iterator<A>() {
647              private int i;
648    
649              public boolean hasNext() {
650                return i < a.length;
651              }
652    
653              public A next() {
654                if (i >= a.length)
655                  throw new NoSuchElementException();
656                else {
657                  final A aa = (A) a[i];
658                  i++;
659                  return aa;
660                }
661              }
662    
663              public void remove() {
664                throw new UnsupportedOperationException();
665              }
666            };
667          }
668    
669          public int size() {
670            return a.length;
671          }
672        };
673      }
674    
675      /**
676       * Takes the given iterable to an array.
677       *
678       * @param i The iterable to take to an array.
679       * @return An array from the given iterable.
680       */
681      public static <A> Array<A> iterableArray(final Iterable<A> i) {
682        return iterableList(i).toArray();
683      }
684    
685      /**
686       * Transforms an array of pairs into an array of first components and an array of second components.
687       *
688       * @param xs The array of pairs to transform.
689       * @return An array of first components and an array of second components.
690       */
691      @SuppressWarnings({"unchecked"})
692      public static <A, B> P2<Array<A>, Array<B>> unzip(final Array<P2<A, B>> xs) {
693        final int len = xs.length();
694        final Array<A> aa = new Array<A>(new Object[len]);
695        final Array<B> ab = new Array<B>(new Object[len]);
696        for (int i = len - 1; i >= 0; i--) {
697          final P2<A, B> p = xs.get(i);
698          aa.set(i, p._1());
699          ab.set(i, p._2());
700        }
701        return P.p(aa, ab);
702      }
703    
704      /**
705       * Projects an array by providing only operations which do not mutate.
706       */
707      public final class ImmutableProjection<A> implements Iterable<A> {
708        private final Array<A> a;
709    
710        private ImmutableProjection(final Array<A> a) {
711          this.a = a;
712        }
713    
714        /**
715         * Returns an iterator for this array. This method exists to permit the use in a <code>for</code>-each loop.
716         *
717         * @return A iterator for this array.
718         */
719        public Iterator<A> iterator() {
720          return a.iterator();
721        }
722    
723        /**
724         * Returns the element at the given index if it exists, fails otherwise.
725         *
726         * @param index The index at which to get the element to return.
727         * @return The element at the given index if it exists, fails otherwise.
728         */
729        public A get(final int index) {
730          return a.get(index);
731        }
732    
733        /**
734         * Returns the length of this array.
735         *
736         * @return The length of this array.
737         */
738        public int length() {
739          return a.length();
740        }
741    
742        /**
743         * Returns <code>true</code> is this array is empty, <code>false</code> otherwise.
744         *
745         * @return <code>true</code> is this array is empty, <code>false</code> otherwise.
746         */
747        public boolean isEmpty() {
748          return a.isEmpty();
749        }
750    
751        /**
752         * Returns <code>false</code> is this array is empty, <code>true</code> otherwise.
753         *
754         * @return <code>false</code> is this array is empty, <code>true</code> otherwise.
755         */
756        public boolean isNotEmpty() {
757          return a.isNotEmpty();
758        }
759    
760        /**
761         * Returns an option projection of this array; <code>None</code> if empty, or the first element
762         * in <code>Some</code>.
763         *
764         * @return An option projection of this array.
765         */
766        public Option<A> toOption() {
767          return a.toOption();
768        }
769    
770        /**
771         * Returns an either projection of this array; the given argument in <code>Left</code> if empty,
772         * or the first element in <code>Right</code>.
773         *
774         * @param x The value to return in left if this array is empty.
775         * @return An either projection of this array.
776         */
777        public <X> Either<X, A> toEither(final P1<X> x) {
778          return a.toEither(x);
779        }
780    
781        /**
782         * Returns a list projection of this array.
783         *
784         * @return A list projection of this array.
785         */
786        public List<A> toList() {
787          return a.toList();
788        }
789    
790        /**
791         * Returns a stream projection of this array.
792         *
793         * @return A stream projection of this array.
794         */
795        public Stream<A> toStream() {
796          return a.toStream();
797        }
798    
799        /**
800         * Maps the given function across this array.
801         *
802         * @param f The function to map across this array.
803         * @return A new array after the given function has been applied to each element.
804         */
805        public <B> Array<B> map(final F<A, B> f) {
806          return a.map(f);
807        }
808    
809        /**
810         * Filters elements from this array by returning only elements which produce <code>true</code>
811         * when the given function is applied to them.
812         *
813         * @param f The predicate function to filter on.
814         * @return A new array whose elements all match the given predicate.
815         */
816        public Array<A> filter(final F<A, Boolean> f) {
817          return a.filter(f);
818        }
819    
820        /**
821         * Performs a side-effect for each element of this array.
822         *
823         * @param f The side-effect to perform for the given element.
824         * @return The unit value.
825         */
826        public Unit foreach(final F<A, Unit> f) {
827          return a.foreach(f);
828        }
829    
830        /**
831         * Performs a right-fold reduction across this array. This function uses O(length) stack space.
832         *
833         * @param f The function to apply on each element of the array.
834         * @param b The beginning value to start the application from.
835         * @return The final result after the right-fold reduction.
836         */
837        public <B> B foldRight(final F<A, F<B, B>> f, final B b) {
838          return a.foldRight(f, b);
839        }
840    
841        /**
842         * Performs a left-fold reduction across this array. This function runs in constant space.
843         *
844         * @param f The function to apply on each element of the array.
845         * @param b The beginning value to start the application from.
846         * @return The final result after the left-fold reduction.
847         */
848        public <B> B foldLeft(final F<B, F<A, B>> f, final B b) {
849          return a.foldLeft(f, b);
850        }
851    
852        /**
853         * Binds the given function across each element of this array with a final join.
854         *
855         * @param f The function to apply to each element of this array.
856         * @return A new array after performing the map, then final join.
857         */
858        public <B> Array<B> bind(final F<A, Array<B>> f) {
859          return a.bind(f);
860        }
861    
862        /**
863         * Performs a bind across each array element, but ignores the element value each time.
864         *
865         * @param bs The array to apply in the final join.
866         * @return A new array after the final join.
867         */
868        public <B> Array<B> sequence(final Array<B> bs) {
869          return a.sequence(bs);
870        }
871    
872        /**
873         * Performs function application within an array (applicative functor pattern).
874         *
875         * @param lf The array of functions to apply.
876         * @return A new array after applying the given array of functions through this array.
877         */
878        public <B> Array<B> apply(final Array<F<A, B>> lf) {
879          return a.apply(lf);
880        }
881    
882        /**
883         * Reverse this array in constant stack space.
884         *
885         * @return A new array that is the reverse of this one.
886         */
887        public Array<A> reverse() {
888          return a.reverse();
889        }
890    
891        /**
892         * Appends the given array to this array.
893         *
894         * @param aas The array to append to this one.
895         * @return A new array that has appended the given array.
896         */
897        public Array<A> append(final Array<A> aas) {
898          return a.append(aas);
899        }
900    
901        /**
902         * Projects an immutable collection of this array.
903         *
904         * @return An immutable collection of this array.
905         */
906        public Collection<A> toCollection() {
907          return a.toCollection();
908        }
909      }
910    }