Skip to content

Commit 83c8aae

Browse files
committed
Try making maybe a sealed interface
1 parent 956b118 commit 83c8aae

File tree

1 file changed

+41
-75
lines changed
  • src/main/java/com/jnape/palatable/lambda/adt

1 file changed

+41
-75
lines changed

src/main/java/com/jnape/palatable/lambda/adt/Maybe.java

Lines changed: 41 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.jnape.palatable.lambda.monad.MonadRec;
1919
import com.jnape.palatable.lambda.traversable.Traversable;
2020

21-
import java.util.Objects;
2221
import java.util.Optional;
2322

2423
import static com.jnape.palatable.lambda.adt.Either.left;
@@ -38,22 +37,20 @@
3837
* @param <A> the optional parameter type
3938
* @see Optional
4039
*/
41-
public abstract class Maybe<A> implements
40+
public sealed interface Maybe<A> extends
4241
CoProduct2<Unit, A, Maybe<A>>,
4342
MonadError<Unit, A, Maybe<?>>,
4443
MonadRec<A, Maybe<?>>,
45-
Traversable<A, Maybe<?>> {
44+
Traversable<A, Maybe<?>> permits Just, Nothing {
4645

47-
private Maybe() {
48-
}
4946

5047
/**
5148
* If the value is present, return it; otherwise, return the value supplied by <code>otherSupplier</code>.
5249
*
5350
* @param otherFn0 the supplier for the other value
5451
* @return this value, or the supplied other value
5552
*/
56-
public final A orElseGet(Fn0<A> otherFn0) {
53+
default A orElseGet(Fn0<A> otherFn0) {
5754
return match(__ -> otherFn0.apply(), id());
5855
}
5956

@@ -63,7 +60,7 @@ public final A orElseGet(Fn0<A> otherFn0) {
6360
* @param other the other value
6461
* @return this value, or the other value
6562
*/
66-
public final A orElse(A other) {
63+
default A orElse(A other) {
6764
return orElseGet(() -> other);
6865
}
6966

@@ -76,7 +73,7 @@ public final A orElse(A other) {
7673
* @return the value, if present
7774
* @throws E the throwable, if the value is absent
7875
*/
79-
public final <E extends Throwable> A orElseThrow(Fn0<? extends E> throwableSupplier) throws E {
76+
default <E extends Throwable> A orElseThrow(Fn0<? extends E> throwableSupplier) throws E {
8077
return orElseGet(fn0(() -> {
8178
throw throwableSupplier.apply();
8279
}));
@@ -89,23 +86,23 @@ public final <E extends Throwable> A orElseThrow(Fn0<? extends E> throwableSuppl
8986
* @param predicate the predicate to apply to the possibly absent value
9087
* @return maybe the present value that satisfied the predicate
9188
*/
92-
public final Maybe<A> filter(Fn1<? super A, ? extends Boolean> predicate) {
89+
default Maybe<A> filter(Fn1<? super A, ? extends Boolean> predicate) {
9390
return flatMap(a -> predicate.apply(a) ? just(a) : nothing());
9491
}
9592

9693
/**
9794
* {@inheritDoc}
9895
*/
9996
@Override
100-
public Maybe<A> throwError(Unit unit) {
97+
default Maybe<A> throwError(Unit unit) {
10198
return nothing();
10299
}
103100

104101
/**
105102
* {@inheritDoc}
106103
*/
107104
@Override
108-
public Maybe<A> catchError(Fn1<? super Unit, ? extends Monad<A, Maybe<?>>> recoveryFn) {
105+
default Maybe<A> catchError(Fn1<? super Unit, ? extends Monad<A, Maybe<?>>> recoveryFn) {
109106
return match(recoveryFn, Maybe::just).coerce();
110107
}
111108

@@ -117,7 +114,7 @@ public Maybe<A> catchError(Fn1<? super Unit, ? extends Monad<A, Maybe<?>>> recov
117114
* @param lFn0 the supplier for the left value
118115
* @return this value wrapped in an Either.right, or an Either.left around the result of lSupplier
119116
*/
120-
public final <L> Either<L, A> toEither(Fn0<L> lFn0) {
117+
default <L> Either<L, A> toEither(Fn0<L> lFn0) {
121118
return fmap(Either::<L, A>right).orElseGet(() -> left(lFn0.apply()));
122119
}
123120

@@ -126,7 +123,7 @@ public final <L> Either<L, A> toEither(Fn0<L> lFn0) {
126123
*
127124
* @return the Optional
128125
*/
129-
public final Optional<A> toOptional() {
126+
default Optional<A> toOptional() {
130127
return fmap(Optional::of).orElseGet(Optional::empty);
131128
}
132129

@@ -138,7 +135,7 @@ public final Optional<A> toOptional() {
138135
* @return Just b
139136
*/
140137
@Override
141-
public final <B> Maybe<B> pure(B b) {
138+
default <B> Maybe<B> pure(B b) {
142139
return just(b);
143140
}
144141

@@ -149,15 +146,15 @@ public final <B> Maybe<B> pure(B b) {
149146
* {@link Maybe#nothing}.
150147
*/
151148
@Override
152-
public final <B> Maybe<B> fmap(Fn1<? super A, ? extends B> fn) {
149+
default <B> Maybe<B> fmap(Fn1<? super A, ? extends B> fn) {
153150
return MonadError.super.<B>fmap(fn).coerce();
154151
}
155152

156153
/**
157154
* {@inheritDoc}
158155
*/
159156
@Override
160-
public final <B> Maybe<B> zip(Applicative<Fn1<? super A, ? extends B>, Maybe<?>> appFn) {
157+
default <B> Maybe<B> zip(Applicative<Fn1<? super A, ? extends B>, Maybe<?>> appFn) {
161158
return MonadError.super.zip(appFn).coerce();
162159
}
163160

@@ -169,7 +166,7 @@ public final <B> Maybe<B> zip(Applicative<Fn1<? super A, ? extends B>, Maybe<?>>
169166
* @return the zipped {@link Maybe}
170167
*/
171168
@Override
172-
public <B> Lazy<Maybe<B>> lazyZip(Lazy<? extends Applicative<Fn1<? super A, ? extends B>, Maybe<?>>> lazyAppFn) {
169+
default <B> Lazy<Maybe<B>> lazyZip(Lazy<? extends Applicative<Fn1<? super A, ? extends B>, Maybe<?>>> lazyAppFn) {
173170
return match(constantly(lazy(nothing())),
174171
a -> lazyAppFn.fmap(maybeF -> maybeF.<B>fmap(f -> f.apply(a)).coerce()));
175172
}
@@ -178,15 +175,15 @@ public <B> Lazy<Maybe<B>> lazyZip(Lazy<? extends Applicative<Fn1<? super A, ? ex
178175
* {@inheritDoc}
179176
*/
180177
@Override
181-
public final <B> Maybe<B> discardL(Applicative<B, Maybe<?>> appB) {
178+
default <B> Maybe<B> discardL(Applicative<B, Maybe<?>> appB) {
182179
return MonadError.super.discardL(appB).coerce();
183180
}
184181

185182
/**
186183
* {@inheritDoc}
187184
*/
188185
@Override
189-
public final <B> Maybe<A> discardR(Applicative<B, Maybe<?>> appB) {
186+
default <B> Maybe<A> discardR(Applicative<B, Maybe<?>> appB) {
190187
return MonadError.super.discardR(appB).coerce();
191188
}
192189

@@ -195,15 +192,15 @@ public final <B> Maybe<A> discardR(Applicative<B, Maybe<?>> appB) {
195192
*/
196193
@SuppressWarnings("RedundantTypeArguments")
197194
@Override
198-
public final <B> Maybe<B> flatMap(Fn1<? super A, ? extends Monad<B, Maybe<?>>> f) {
195+
default <B> Maybe<B> flatMap(Fn1<? super A, ? extends Monad<B, Maybe<?>>> f) {
199196
return match(constantly(nothing()), f.fmap(Monad<B, Maybe<?>>::coerce));
200197
}
201198

202199
/**
203200
* {@inheritDoc}
204201
*/
205202
@Override
206-
public <B> Maybe<B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveResult<A, B>, Maybe<?>>> fn) {
203+
default <B> Maybe<B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveResult<A, B>, Maybe<?>>> fn) {
207204
return match(constantly(nothing()), trampoline(a -> fn.apply(a).<Maybe<RecursiveResult<A, B>>>coerce()
208205
.match(constantly(terminate(nothing())),
209206
aOrB -> aOrB.fmap(Maybe::just))));
@@ -213,23 +210,23 @@ public <B> Maybe<B> trampolineM(Fn1<? super A, ? extends MonadRec<RecursiveResul
213210
* {@inheritDoc}
214211
*/
215212
@Override
216-
public <B> Choice3<Unit, A, B> diverge() {
213+
default <B> Choice3<Unit, A, B> diverge() {
217214
return match(Choice3::a, Choice3::b);
218215
}
219216

220217
/**
221218
* {@inheritDoc}
222219
*/
223220
@Override
224-
public Tuple2<Maybe<Unit>, Maybe<A>> project() {
221+
default Tuple2<Maybe<Unit>, Maybe<A>> project() {
225222
return CoProduct2.super.project().into(HList::tuple);
226223
}
227224

228225
/**
229226
* {@inheritDoc}
230227
*/
231228
@Override
232-
public Choice2<A, Unit> invert() {
229+
default Choice2<A, Unit> invert() {
233230
return match(Choice2::b, Choice2::a);
234231
}
235232

@@ -241,13 +238,13 @@ public Choice2<A, Unit> invert() {
241238
* @deprecated in favor of {@link Maybe#match(Fn1, Fn1) matching} into an {@link IO} and explicitly running it
242239
*/
243240
@Deprecated
244-
public final Maybe<A> peek(Fn1<? super A, ? extends IO<?>> effect) {
241+
default Maybe<A> peek(Fn1<? super A, ? extends IO<?>> effect) {
245242
return match(constantly(io(this)), a -> effect.apply(a).fmap(constantly(this))).unsafePerformIO();
246243
}
247244

248245
@Override
249246
@SuppressWarnings("unchecked")
250-
public final <B, App extends Applicative<?, App>, TravB extends Traversable<B, Maybe<?>>,
247+
default <B, App extends Applicative<?, App>, TravB extends Traversable<B, Maybe<?>>,
251248
AppTrav extends Applicative<TravB, App>> AppTrav traverse(Fn1<? super A, ? extends Applicative<B, App>> fn,
252249
Fn1<? super TravB, ? extends AppTrav> pure) {
253250
return match(__ -> pure.apply((TravB) Maybe.<B>nothing()), a -> (AppTrav) fn.apply(a).fmap(Maybe::just));
@@ -261,7 +258,7 @@ AppTrav extends Applicative<TravB, App>> AppTrav traverse(Fn1<? super A, ? exten
261258
* @param <A> the potential right value
262259
* @return "Just" the right value, or nothing
263260
*/
264-
public static <A> Maybe<A> fromEither(Either<?, A> either) {
261+
static <A> Maybe<A> fromEither(Either<?, A> either) {
265262
return either.toMaybe();
266263
}
267264

@@ -272,7 +269,7 @@ public static <A> Maybe<A> fromEither(Either<?, A> either) {
272269
* @param <A> the optional parameter type
273270
* @return the equivalent Maybe instance
274271
*/
275-
public static <A> Maybe<A> fromOptional(Optional<? extends A> optional) {
272+
static <A> Maybe<A> fromOptional(Optional<? extends A> optional) {
276273
return optional.map(Maybe::<A>just).orElse(Maybe.nothing());
277274
}
278275

@@ -284,7 +281,7 @@ public static <A> Maybe<A> fromOptional(Optional<? extends A> optional) {
284281
* @param <A> the value parameter type
285282
* @return "Just" the value, or nothing
286283
*/
287-
public static <A> Maybe<A> maybe(A a) {
284+
static <A> Maybe<A> maybe(A a) {
288285
return a == null ? nothing() : just(a);
289286
}
290287

@@ -297,7 +294,7 @@ public static <A> Maybe<A> maybe(A a) {
297294
* @return "Just" the value
298295
* @throws NullPointerException if a is null
299296
*/
300-
public static <A> Maybe<A> just(A a) {
297+
static <A> Maybe<A> just(A a) {
301298
if (a == null)
302299
throw new NullPointerException();
303300
return new Just<>(a);
@@ -310,7 +307,7 @@ public static <A> Maybe<A> just(A a) {
310307
* @return nothing
311308
*/
312309
@SuppressWarnings("unchecked")
313-
public static <A> Maybe<A> nothing() {
310+
static <A> Maybe<A> nothing() {
314311
return (Maybe<A>) Nothing.INSTANCE;
315312
}
316313

@@ -319,53 +316,22 @@ public static <A> Maybe<A> nothing() {
319316
*
320317
* @return the {@link Pure} instance
321318
*/
322-
public static Pure<Maybe<?>> pureMaybe() {
319+
static Pure<Maybe<?>> pureMaybe() {
323320
return Maybe::just;
324321
}
322+
}
323+
record Nothing<A>() implements Maybe<A> {
324+
static final Nothing<?> INSTANCE = new Nothing<>();
325325

326-
private static final class Nothing<A> extends Maybe<A> {
327-
private static final Nothing<?> INSTANCE = new Nothing<>();
328-
329-
private Nothing() {
330-
}
331-
332-
@Override
333-
public <R> R match(Fn1<? super Unit, ? extends R> aFn, Fn1<? super A, ? extends R> bFn) {
334-
return aFn.apply(UNIT);
335-
}
336-
337-
@Override
338-
public String toString() {
339-
return "Nothing";
340-
}
326+
@Override
327+
public <R> R match(Fn1<? super Unit, ? extends R> aFn, Fn1<? super A, ? extends R> bFn) {
328+
return aFn.apply(UNIT);
341329
}
330+
}
342331

343-
private static final class Just<A> extends Maybe<A> {
344-
345-
private final A a;
346-
347-
private Just(A a) {
348-
this.a = a;
349-
}
350-
351-
@Override
352-
public <R> R match(Fn1<? super Unit, ? extends R> aFn, Fn1<? super A, ? extends R> bFn) {
353-
return bFn.apply(a);
354-
}
355-
356-
@Override
357-
public boolean equals(Object other) {
358-
return other instanceof Just && Objects.equals(this.a, ((Just) other).a);
359-
}
360-
361-
@Override
362-
public int hashCode() {
363-
return Objects.hash(a);
364-
}
365-
366-
@Override
367-
public String toString() {
368-
return "Just " + a;
369-
}
332+
record Just<A>(A a) implements Maybe<A> {
333+
@Override
334+
public <R> R match(Fn1<? super Unit, ? extends R> aFn, Fn1<? super A, ? extends R> bFn) {
335+
return bFn.apply(a);
370336
}
371-
}
337+
}

0 commit comments

Comments
 (0)