001 package fj; 002 003 import fj.data.List; 004 import fj.data.Stream; 005 import fj.data.Array; 006 import fj.data.Option; 007 import static fj.data.Option.none; 008 import static fj.data.Option.some; 009 import static fj.data.Option.fromNull; 010 011 import java.util.concurrent.CountDownLatch; 012 import java.util.concurrent.atomic.AtomicReference; 013 import java.lang.ref.WeakReference; 014 import java.lang.ref.SoftReference; 015 016 /** 017 * A product-1. Also, the identity monad. 018 * 019 * @version %build.number%<br> 020 * <ul> 021 * <li>$LastChangedRevision: 273 $</li> 022 * <li>$LastChangedDate: 2009-08-04 06:25:29 +1000 (Tue, 04 Aug 2009) $</li> 023 * </ul> 024 */ 025 public abstract class P1<A> { 026 /** 027 * Access the first element of the product. 028 * 029 * @return The first element of the product. 030 */ 031 public abstract A _1(); 032 033 /** 034 * Map the element of the product. 035 * 036 * @param f The function to map with. 037 * @return A product with the given function applied. 038 */ 039 public <X> P1<X> map(final F<A, X> f) { 040 return new P1<X>() { 041 public X _1() { 042 return f.f(P1.this._1()); 043 } 044 }; 045 } 046 047 /** 048 * Returns a function that returns the first element of a product. 049 * 050 * @return A function that returns the first element of a product. 051 */ 052 public static <A> F<P1<A>, A> __1() { 053 return new F<P1<A>, A>() { 054 public A f(final P1<A> p) { 055 return p._1(); 056 } 057 }; 058 } 059 060 /** 061 * Promote any function to a transformation between P1s. 062 * 063 * @param f A function to promote to a transformation between P1s. 064 * @return A function promoted to operate on P1s. 065 */ 066 public static <A, B> F<P1<A>, P1<B>> fmap(final F<A, B> f) { 067 return new F<P1<A>, P1<B>>() { 068 public P1<B> f(final P1<A> a) { 069 return a.map(f); 070 } 071 }; 072 } 073 074 /** 075 * Binds the given function to the value in a product-1 with a final join. 076 * 077 * @param a A value in a product-1 to which to apply a function. 078 * @param f A function to apply to the value in a product-1. 079 * @return The result of applying the given function to the value of given product-1. 080 */ 081 public static <A, B> P1<B> bind(final P1<A> a, final F<A, P1<B>> f) { 082 return new P1<B>() { 083 public B _1() { 084 return f.f(a._1())._1(); 085 } 086 }; 087 } 088 089 /** 090 * Promotes the given function so that it returns its value in a P1. 091 * 092 * @param f A function to have its result wrapped in a P1. 093 * @return A function whose result is wrapped in a P1. 094 */ 095 public static <A, B> F<A, P1<B>> curry(final F<A, B> f) { 096 return new F<A, P1<B>>() { 097 public P1<B> f(final A a) { 098 return new P1<B>() { 099 public B _1() { 100 return f.f(a); 101 } 102 }; 103 } 104 }; 105 } 106 107 /** 108 * Performs function application within a P1 (applicative functor pattern). 109 * 110 * @param ca The P1 to which to apply a function. 111 * @param cf The P1 function to apply. 112 * @return A new P1 after applying the given P1 function to the first argument. 113 */ 114 public static <A, B> P1<B> apply(final P1<A> ca, final P1<F<A, B>> cf) { 115 return bind(cf, new F<F<A, B>, P1<B>>() { 116 public P1<B> f(final F<A, B> f) { 117 return fmap(f).f(ca); 118 } 119 }); 120 } 121 122 /** 123 * Binds the given function to the values in the given P1s with a final join. 124 * 125 * @param ca A given P1 to bind the given function with. 126 * @param cb A given P1 to bind the given function with. 127 * @param f The function to apply to the values in the given P1s. 128 * @return A new P1 after performing the map, then final join. 129 */ 130 public static <A, B, C> P1<C> bind(final P1<A> ca, final P1<B> cb, final F<A, F<B, C>> f) { 131 return apply(cb, fmap(f).f(ca)); 132 } 133 134 /** 135 * Joins a P1 of a P1 with a bind operation. 136 * 137 * @param a The P1 of a P1 to join. 138 * @return A new P1 that is the join of the given P1. 139 */ 140 public static <A> P1<A> join(final P1<P1<A>> a) { 141 return bind(a, Function.<P1<A>>identity()); 142 } 143 144 /** 145 * Promotes a function of arity-2 to a function on P1s. 146 * 147 * @param f The function to promote. 148 * @return A function of arity-2 promoted to map over P1s. 149 */ 150 public static <A, B, C> F<P1<A>, F<P1<B>, P1<C>>> liftM2(final F<A, F<B, C>> f) { 151 return Function.curry(new F2<P1<A>, P1<B>, P1<C>>() { 152 public P1<C> f(final P1<A> pa, final P1<B> pb) { 153 return bind(pa, pb, f); 154 } 155 }); 156 } 157 158 /** 159 * Turns a List of P1s into a single P1 of a List. 160 * 161 * @param as The list of P1s to transform. 162 * @return A single P1 for the given List. 163 */ 164 public static <A> P1<List<A>> sequence(final List<P1<A>> as) { 165 return as.foldRight(liftM2(List.<A>cons()), P.p(List.<A>nil())); 166 } 167 168 /** 169 * A first-class version of the sequence method for lists of P1s. 170 * 171 * @return A function from a List of P1s to a single P1 of a List. 172 */ 173 public static <A> F<List<P1<A>>, P1<List<A>>> sequenceList() { 174 return new F<List<P1<A>>, P1<List<A>>>() { 175 public P1<List<A>> f(final List<P1<A>> as) { 176 return sequence(as); 177 } 178 }; 179 } 180 181 /** 182 * Turns a stream of P1s into a single P1 of a stream. 183 * 184 * @param as The stream of P1s to transform. 185 * @return A single P1 for the given stream. 186 */ 187 public static <A> P1<Stream<A>> sequence(final Stream<P1<A>> as) { 188 return as.foldRight(liftM2(Stream.<A>cons()), P.p(Stream.<A>nil())); 189 } 190 191 /** 192 * Turns an array of P1s into a single P1 of an array. 193 * 194 * @param as The array of P1s to transform. 195 * @return A single P1 for the given array. 196 */ 197 public static <A> P1<Array<A>> sequence(final Array<P1<A>> as) { 198 return new P1<Array<A>>() { 199 public Array<A> _1() { 200 return as.map(P1.<A>__1()); 201 } 202 }; 203 } 204 205 /** 206 * Provides a memoising P1 that remembers its value. 207 * 208 * @return A P1 that calls this P1 once and remembers the value for subsequent calls. 209 */ 210 public P1<A> memo() { 211 final P1<A> self = this; 212 return new P1<A>() { 213 private Object latch = new Object(); 214 private volatile SoftReference<A> v; 215 216 public A _1() { 217 A a = v != null ? v.get() : null; 218 if (a == null) 219 synchronized (latch) { 220 if (v == null || v.get() == null) 221 a = self._1(); 222 v = new SoftReference<A>(a); 223 } 224 return a; 225 } 226 }; 227 } 228 229 }