001    package fj.data.vector;
002    
003    import fj.F;
004    import fj.F2;
005    import static fj.Function.curry;
006    import static fj.P.p2;
007    import fj.P1;
008    import fj.P2;
009    import fj.data.Array;
010    import fj.data.List;
011    import fj.data.NonEmptyList;
012    import fj.data.Stream;
013    
014    import java.util.Iterator;
015    
016    /**
017     * A vector-2.
018     */
019    public final class V2<A> implements Iterable<A> {
020    
021      private final P2<A, A> inner;
022    
023      private V2(final P2<A, A> inner) {
024        this.inner = inner;
025      }
026    
027      /**
028       * Creates a vector-2 from a homogeneous product-2.
029       *
030       * @param p The product-2 from which to create a vector.
031       * @return A new vector-2.
032       */
033      public static <A> V2<A> p(final P2<A, A> p) {
034        return new V2<A>(p);
035      }
036    
037      /**
038       * Returns the first element of this vector.
039       *
040       * @return the first element of this vector.
041       */
042      public A _1() {
043        return inner._1();
044      }
045    
046      /**
047       * Returns the second element of this vector.
048       *
049       * @return the second element of this vector.
050       */
051      public A _2() {
052        return inner._2();
053      }
054    
055      /**
056       * A first-class function to get the first element of a vector.
057       *
058       * @return a function that gets the first element of a given vector.
059       */
060      public static <A> F<V2<A>, A> __1() {
061        return new F<V2<A>, A>() {
062          public A f(final V2<A> v) {
063            return v._1();
064          }
065        };
066      }
067    
068      /**
069       * A first-class function to get the second element of a vector.
070       *
071       * @return a function that gets the second element of a given vector.
072       */
073      public static <A> F<V2<A>, A> __2() {
074        return new F<V2<A>, A>() {
075          public A f(final V2<A> v) {
076            return v._2();
077          }
078        };
079      }
080    
081      /**
082       * Returns an iterator for the elements of this vector.
083       *
084       * @return an iterator for the elements of this vector.
085       */
086      public Iterator<A> iterator() {
087        return toStream().iterator();
088      }
089    
090      /**
091       * Returns a homogeneous product-2 equivalent to this vector.
092       *
093       * @return a homogeneous product-2 equivalent to this vector.
094       */
095      public P2<A, A> p() {
096        return inner;
097      }
098    
099      /**
100       * Returns a nonempty list with the elements of this vector.
101       *
102       * @return a nonempty list with the elements of this vector.
103       */
104      public NonEmptyList<A> toNonEmptyList() {
105        return NonEmptyList.nel(_1(), List.single(_2()));
106      }
107    
108      /**
109       * Returns a stream of the elements of this vector.
110       *
111       * @return a stream of the elements of this vector.
112       */
113      public Stream<A> toStream() {
114        return Stream.cons(_1(), new P1<Stream<A>>() {
115          public Stream<A> _1() {
116            return Stream.single(_2());
117          }
118        });
119      }
120    
121      /**
122       * Returns a function that transforms a vector-2 to a stream of its elements.
123       *
124       * @return a function that transforms a vector-2 to a stream of its elements.
125       */
126      public static <A> F<V2<A>, Stream<A>> toStream_() {
127        return new F<V2<A>, Stream<A>>() {
128          public Stream<A> f(final V2<A> v) {
129            return v.toStream();
130          }
131        };
132      }
133    
134      /**
135       * Returns a function that transforms a vector-2 to the equivalent product-2.
136       *
137       * @return a function that transforms a vector-2 to the equivalent product-2.
138       */
139      public static <A> F<V2<A>, P2<A, A>> p_() {
140        return new F<V2<A>, P2<A, A>>() {
141          public P2<A, A> f(final V2<A> v) {
142            return v.p();
143          }
144        };
145      }
146    
147      /**
148       * Returns an array with the elements of this vector.
149       *
150       * @return an array with the elements of this vector.
151       */
152      @SuppressWarnings("unchecked")
153      public Array<A> toArray() {
154        return Array.array(_1(), _2());
155      }
156    
157      /**
158       * Maps the given function across this vector.
159       *
160       * @param f The function to map across this vector.
161       * @return A new vector after the given function has been applied to each element.
162       */
163      public <B> V2<B> map(final F<A, B> f) {
164        return p(inner.split(f, f));
165      }
166    
167      /**
168       * Performs function application within a vector (applicative functor pattern).
169       *
170       * @param vf The vector of functions to apply.
171       * @return A new vector after zipping the given vector of functions over this vector.
172       */
173      public <B> V2<B> apply(final V2<F<A, B>> vf) {
174        return p(inner.split(vf._1(), vf._2()));
175      }
176    
177      /**
178       * Zips this vector with the given vector using the given function to produce a new vector.
179       *
180       * @param bs The vector to zip this vector with.
181       * @param f  The function to zip this vector and the given vector with.
182       * @return A new vector with the results of the function.
183       */
184      public <B, C> V2<C> zipWith(final F<A, F<B, C>> f, final V2<B> bs) {
185        return bs.apply(map(f));
186      }
187    
188      /**
189       * Zips this vector with the given vector to produce a vector of pairs.
190       *
191       * @param bs The vector to zip this vector with.
192       * @return A new vector with a length the same as the shortest of this vector and the given
193       *         vector.
194       */
195      public <B> V2<P2<A, B>> zip(final V2<B> bs) {
196        final F<A, F<B, P2<A, B>>> __2 = p2();
197        return zipWith(__2, bs);
198      }
199    
200      /**
201       * Zips this vector with the given vector to produce a vector of vectors.
202       *
203       * @param bs The vector to zip this vector with.
204       * @return A new vector of vectors.
205       */
206      public V2<V2<A>> vzip(final V2<A> bs) {
207        final F2<A, A, V2<A>> __2 = V.v2();
208        return zipWith(curry(__2), bs);
209      }
210    
211      /**
212       * Return the first element of this vector as a product-1.
213       *
214       * @return the first element of this vector as a product-1.
215       */
216      public P1<A> head() {
217        return new P1<A>() {
218          public A _1() {
219            return V2.this._1();
220          }
221        };
222      }
223    
224    }