001    package fj.data.vector;
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 static fj.Function.curry;
010    import static fj.P.p2;
011    import fj.data.Array;
012    import fj.data.NonEmptyList;
013    import fj.data.Stream;
014    
015    import java.util.Iterator;
016    
017    /**
018     * A vector-4.
019     */
020    public final class V4<A> implements Iterable<A> {
021    
022      private final V3<A> tail;
023      private final P1<A> head;
024    
025      private V4(final P1<A> head, final V3<A> tail) {
026        this.head = head;
027        this.tail = tail;
028      }
029    
030      /**
031       * Creates a vector-4 from a homogeneous product-4.
032       *
033       * @param p The product-4 from which to create a vector.
034       * @return A new vector-4.
035       */
036      public static <A> V4<A> p(final P4<A, A, A, A> p) {
037        return new V4<A>(new P1<A>() {
038          public A _1() {
039            return p._1();
040          }
041        }, V3.p(new P3<A, A, A>() {
042          public A _1() {
043            return p._2();
044          }
045    
046          public A _2() {
047            return p._3();
048          }
049    
050          public A _3() {
051            return p._4();
052          }
053        }));
054      }
055    
056      /**
057       * Creates a vector-4 from a head and a tail.
058       *
059       * @param head The value to put as the first element of the vector.
060       * @param tail The vector representing all but the first element of the new vector.
061       * @return The new vector.
062       */
063      public static <A> V4<A> cons(final P1<A> head, final V3<A> tail) {
064        return new V4<A>(head, tail);
065      }
066    
067      /**
068       * Returns the first element of this vector.
069       *
070       * @return the first element of this vector.
071       */
072      public A _1() {
073        return head._1();
074      }
075    
076      /**
077       * Returns the second element of this vector.
078       *
079       * @return the second element of this vector.
080       */
081      public A _2() {
082        return tail._1();
083      }
084    
085      /**
086       * Returns the third element of this vector.
087       *
088       * @return the third element of this vector.
089       */
090      public A _3() {
091        return tail._2();
092      }
093    
094      /**
095       * Returns the fourth element of this vector.
096       *
097       * @return the fourth element of this vector.
098       */
099      public A _4() {
100        return tail._3();
101      }
102    
103      /**
104       * Returns all but the first element of this vector, as a vector-3.
105       *
106       * @return all but the first element of this vector, as a vector-3.
107       */
108      public V3<A> tail() {
109        return tail;
110      }
111    
112      /**
113       * Returns the first element of this vector, as a product-1.
114       *
115       * @return the first element of this vector, as a product-1.
116       */
117      public P1<A> head() {
118        return head;
119      }
120    
121      /**
122       * Returns an iterator for the elements of this vector.
123       *
124       * @return an iterator for the elements of this vector.
125       */
126      public Iterator<A> iterator() {
127        return toStream().iterator();
128      }
129    
130      /**
131       * Returns a homogeneous product-4 equivalent to this vector.
132       *
133       * @return a homogeneous product-4 equivalent to this vector.
134       */
135      public P4<A, A, A, A> p() {
136        return new P4<A, A, A, A>() {
137          public A _1() {
138            return V4.this._1();
139          }
140    
141          public A _2() {
142            return V4.this._2();
143          }
144    
145          public A _3() {
146            return V4.this._3();
147          }
148    
149          public A _4() {
150            return V4.this._4();
151          }
152        };
153      }
154    
155      /**
156       * Returns a nonempty list with the elements of this vector.
157       *
158       * @return a nonempty list with the elements of this vector.
159       */
160      public NonEmptyList<A> toNonEmptyList() {
161        return NonEmptyList.nel(_1(), tail.toNonEmptyList().toList());
162      }
163    
164      /**
165       * Returns a stream of the elements of this vector.
166       *
167       * @return a stream of the elements of this vector.
168       */
169      public Stream<A> toStream() {
170        return Stream.cons(head._1(), new P1<Stream<A>>() {
171          public Stream<A> _1() {
172            return tail.toStream();
173          }
174        });
175      }
176    
177      /**
178       * Returns an array with the elements of this vector.
179       *
180       * @return an array with the elements of this vector.
181       */
182      @SuppressWarnings("unchecked")
183      public Array<A> toArray() {
184        return Array.array(_1(), _2(), _3(), _4());
185      }
186    
187      /**
188       * Maps the given function across this vector.
189       *
190       * @param f The function to map across this vector.
191       * @return A new vector after the given function has been applied to each element.
192       */
193      public <B> V4<B> map(final F<A, B> f) {
194        return new V4<B>(head.map(f), tail.map(f));
195      }
196    
197      /**
198       * Performs function application within a vector (applicative functor pattern).
199       *
200       * @param vf The vector of functions to apply.
201       * @return A new vector after zipping the given vector of functions over this vector.
202       */
203      public <B> V4<B> apply(final V4<F<A, B>> vf) {
204        return new V4<B>(P1.<A, B>apply(head, vf.head()), tail.apply(vf.tail()));
205      }
206    
207      /**
208       * Zips this vector with the given vector using the given function to produce a new vector.
209       *
210       * @param bs The vector to zip this vector with.
211       * @param f  The function to zip this vector and the given vector with.
212       * @return A new vector with the results of the function.
213       */
214      public <B, C> V4<C> zipWith(final F<A, F<B, C>> f, final V4<B> bs) {
215        return bs.apply(map(f));
216      }
217    
218      /**
219       * Zips this vector with the given vector to produce a vector of pairs.
220       *
221       * @param bs The vector to zip this vector with.
222       * @return A new vector with a length the same as the shortest of this vector and the given
223       *         vector.
224       */
225      public <B> V4<P2<A, B>> zip(final V4<B> bs) {
226        final F<A, F<B, P2<A, B>>> __2 = p2();
227        return zipWith(__2, bs);
228      }
229    
230      /**
231       * Zips this vector with the given vector to produce a vector of vectors.
232       *
233       * @param bs The vector to zip this vector with.
234       * @return A new vector of vectors.
235       */
236      public V4<V2<A>> vzip(final V4<A> bs) {
237        final F2<A, A, V2<A>> __2 = V.v2();
238        return zipWith(curry(__2), bs);
239      }
240    
241      /**
242       * Returns a function that transforms a vector-4 to a stream of its elements.
243       *
244       * @return a function that transforms a vector-4 to a stream of its elements.
245       */
246      public static <A> F<V4<A>, Stream<A>> toStream_() {
247        return new F<V4<A>, Stream<A>>() {
248          public Stream<A> f(final V4<A> v) {
249            return v.toStream();
250          }
251        };
252      }
253    
254      /**
255       * Returns a function that transforms a vector-4 to the equivalent product-4.
256       *
257       * @return a function that transforms a vector-4 to the equivalent product-4.
258       */
259      public static <A> F<V4<A>, P4<A, A, A, A>> p_() {
260        return new F<V4<A>, P4<A, A, A, A>>() {
261          public P4<A, A, A, A> f(final V4<A> v) {
262            return v.p();
263          }
264        };
265      }
266    
267      /**
268       * A first-class function to get the first element of a vector.
269       *
270       * @return a function that gets the first element of a given vector.
271       */
272      public static <A> F<V4<A>, A> __1() {
273        return new F<V4<A>, A>() {
274          public A f(final V4<A> v) {
275            return v._1();
276          }
277        };
278      }
279    
280      /**
281       * A first-class function to get the second element of a vector.
282       *
283       * @return a function that gets the second element of a given vector.
284       */
285      public static <A> F<V4<A>, A> __2() {
286        return new F<V4<A>, A>() {
287          public A f(final V4<A> v) {
288            return v._2();
289          }
290        };
291      }
292    
293      /**
294       * A first-class function to get the third element of a vector.
295       *
296       * @return a function that gets the third element of a given vector.
297       */
298      public static <A> F<V4<A>, A> __3() {
299        return new F<V4<A>, A>() {
300          public A f(final V4<A> v) {
301            return v._3();
302          }
303        };
304      }
305    
306      /**
307       * A first-class function to get the third element of a vector.
308       *
309       * @return a function that gets the third element of a given vector.
310       */
311      public static <A> F<V4<A>, A> __4() {
312        return new F<V4<A>, A>() {
313          public A f(final V4<A> v) {
314            return v._4();
315          }
316        };
317      }
318    }