View Javadoc
1   package io.atlassian.fugue.extensions.step;
2   
3   import io.atlassian.fugue.Either;
4   import io.atlassian.fugue.Option;
5   import io.atlassian.fugue.Try;
6   
7   import java.util.Optional;
8   
9   /**
10   * This provides an entry point for a "for-comprehension" styled syntax shortcut
11   * of fugue {@link Option}, {@link Either}, {@link Try} and Java 8
12   * {@link Optional}.
13   * <p>
14   * The intention of this comprehension is to provide access to flatMap, map and
15   * filter of these <i>monad</i> types in a way that is easier to read and reason
16   * about.
17   * <p>
18   * A short explanation is:
19   *
20   * <ul>
21   * <li>Each step must preserve the shape of the original monad. For example if
22   * you begin with an {@link Option} then each step must return an {@link Option}
23   * with the final yield producing an {@link Option} result.</li>
24   * <li>Each step retains access to the previously defined/success values</li>
25   * <li>On the first empty/failure step result, no further steps will be
26   * evaluated</li>
27   * <li>Filter provides a convenience method to break out of further evaluation</li>
28   * </ul>
29   * <p>
30   * Simple example usage of Steps to produce an {@link Option} by chaining
31   * functions that all have access to the previous values.
32   * <p>
33   * {@code
34   * Option<Integer> result = Steps.begin(some(2))
35   * .then(number -> some(number + 3))
36   * .then((number1, number2) -> some(number1 * number2))
37   * .yield((number1, number2, number3) -> number3 * 4);
38   * }
39   * <p>
40   * This yield will produce a {@link io.atlassian.fugue.Option#some} containing
41   * the final value of 40.
42   * <p>
43   * This is calculated by:
44   *
45   * <ol>
46   * <li>The initial defined state of the option is 2</li>
47   * <li>This value of 2 is given parameter name of number for the first step, and
48   * is added to 3, producing 5</li>
49   * <li>The next step accepts both parameters (2 and 5) and multiplies them
50   * together, and returns this value of 10</li>
51   * <li>The final yield accepts all 3 parameters (2, 5, 10) but only cares about
52   * the 3rd parameter (10) and multiplies this by 4 to produce 40</li>
53   * <li>The result option is now a <code>some</code> of 40</li>
54   * </ol>
55   * <p>
56   * An example of a Steps causing it to break out early, and do no further
57   * evaluation is:
58   * <p>
59   * {@code
60   * Option<Integer> result = Steps.begin(some(2))
61   * .then(number -> none(Integer.class))
62   * .then((number1, number2) -> some(number1 * number2))
63   * .yield((number1, number2, number3) -> number3 * 4);
64   * }
65   * <p>
66   * In this example, the result will be <code>none</code> and the functions after
67   * the empty state is returned will not be evaluated.
68   * <p>
69   * While each step provides access to the previous values, if these are not
70   * required, then it is possible to evaluate a new value using a Supplier at
71   * each step. For example, the following is possible:
72   * <p>
73   * {@code
74   * Option<Integer> result = Steps.begin(some(2))
75   * .then(() -> some(5))
76   * .then((number1, number2) -> some(number1 * number2))
77   * .yield((number1, number2, number3) -> number3 * 4);
78   * }
79   * <p>
80   * In this case we have decided that the first step will evaluate its result
81   * without requiring the previous state, and just return 5. This final result
82   * will still be a <code>some</code> of 40.
83   * <p>
84   * Filter is another method to break out of further evaulations and return the
85   * empty result. The following example, illustrates this:
86   * <p>
87   * {@code
88   * Option<Integer> result = Steps.begin(some(2))
89   * .then(number -> some(number + 3))
90   * .filter((number1, number2) -> number2 == 0)
91   * .then((number1, number2) -> some(number1 * number2))
92   * .yield((number1, number2, number3) -> number3 * 4);
93   * }
94   * <p>
95   * In this contrived example, the filter predicate will return false as number2
96   * will always be 5, and never 0. This will result in that steps result being
97   * changed to the empty value, and prevent any further step evaluation.
98   * <p>
99   * NB: It is possible to chain together up to 6 steps
100  *
101  * @see Option
102  * @see Either
103  * @see Try
104  * @see Optional
105  * @since 4.7.0
106  */
107 public final class Steps {
108 
109   private Steps() {
110     // do not instantiate
111   }
112 
113   /**
114    * Begin a new Steps expresison, using the {@link Either} type.
115    * <p>
116    * This assumes a Right-Biased Either, and will therefore continue evaluating
117    * steps on <code>right</code> results, and break out early on the first
118    * <code>left</code> result.
119    *
120    * @param either The start value for this steps.
121    * @param <A> The right hand side type for the initial {@link Either}
122    * @param <LEFT> The left hand side type for the initial {@link Either}
123    * @return A class allowing continuation of this first Step
124    * @see Either
125    * @see Steps for description of Steps usage with examples
126    */
127   public static <A, LEFT> EitherStep1<A, LEFT> begin(Either<LEFT, A> either) {
128     return new EitherStep1<>(either);
129   }
130 
131   /**
132    * Begin a new Steps expresison, using the {@link Option} type.
133    * <p>
134    * This will continue evaluating steps on <code>some</code> results, and break
135    * out early on the first <code>none</code> result.
136    *
137    * @param option The start value for this steps.
138    * @param <A> The type for the initial {@link Option}
139    * @return A class allowing continuation of this first Step
140    * @see Option
141    * @see Steps for description of Steps usage with examples
142    */
143   public static <A> OptionStep1<A> begin(Option<A> option) {
144     return new OptionStep1<>(option);
145   }
146 
147   /**
148    * Begin a new Steps expresison, using the {@link Optional} type.
149    * <p>
150    * This will continue evaluating steps on <code>of</code> results, and break
151    * out early on the first <code>empty</code> result.
152    *
153    * @param optional The start value for this steps.
154    * @param <A> The type for the initial {@link Optional}
155    * @return A class allowing continuation of this first Step
156    * @see Optional
157    * @see Steps for description of Steps usage with examples
158    */
159   @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public static <A> OptionalStep1<A> begin(Optional<A> optional) {
160     return new OptionalStep1<>(optional);
161   }
162 
163   /**
164    * Begin a new Steps expresison, using the {@link Try} type.
165    * <p>
166    * This will continue evaluating steps on <code>success</code> results, and
167    * break out early on the first <code>failure</code> result.
168    *
169    * @param aTry The start value for this steps.
170    * @param <A> The type for the initial {@link Try}
171    * @return A class allowing continuation of this first Step
172    * @see Try
173    * @see Steps for description of Steps usage with examples
174    */
175   public static <A> TryStep1<A> begin(Try<A> aTry) {
176     return new TryStep1<>(aTry);
177   }
178 
179 }