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