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