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 }