Skip to content

Commit cb99e09

Browse files
Fixes #403. Add fj.data.Option.sequence*, fj.data.Option.traverse*.
1 parent 848e2c0 commit cb99e09

File tree

2 files changed

+515
-78
lines changed

2 files changed

+515
-78
lines changed

core/src/main/java/fj/data/Option.java

Lines changed: 297 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,24 @@
11
package fj.data;
22

3-
import static fj.Bottom.error;
4-
import fj.F;
5-
import fj.F0;
6-
import fj.F2;
7-
import fj.P;
8-
import fj.P1;
9-
import fj.P2;
10-
import fj.P3;
11-
import fj.P4;
12-
import fj.P5;
13-
import fj.P6;
14-
import fj.P7;
15-
import fj.P8;
16-
import fj.Unit;
17-
import fj.Show;
3+
import fj.*;
4+
import fj.control.Trampoline;
5+
import fj.data.optic.*;
186
import fj.function.Effect1;
19-
import fj.Equal;
20-
import fj.Ord;
21-
import fj.Hash;
22-
import fj.data.optic.Prism;
23-
import fj.data.optic.PPrism;
7+
8+
import java.lang.Class;
9+
import java.util.*;
10+
11+
import static fj.Bottom.error;
2412
import static fj.Function.*;
2513
import static fj.P.p;
14+
import static fj.Show.optionShow;
2615
import static fj.Unit.unit;
27-
import static fj.data.List.cons;
28-
import static fj.data.List.cons_;
29-
import static fj.data.Validation.parseByte;
30-
import static fj.data.Validation.parseDouble;
31-
import static fj.data.Validation.parseFloat;
32-
import static fj.data.Validation.parseInt;
33-
import static fj.data.Validation.parseLong;
34-
import static fj.data.Validation.parseShort;
35-
import static fj.data.optic.Prism.prism;
16+
import static fj.control.Trampoline.pure;
17+
import static fj.data.Either.*;
18+
import static fj.data.List.*;
19+
import static fj.data.Validation.*;
3620
import static fj.data.optic.PPrism.pPrism;
37-
import static fj.Show.optionShow;
38-
39-
import java.util.Collection;
40-
import java.util.Iterator;
21+
import static fj.data.optic.Prism.prism;
4122

4223
/**
4324
* An optional value that may be none (no value) or some (a value). This type is a replacement for
@@ -411,45 +392,307 @@ public final <B> Option<B> sequence(final Option<B> o) {
411392
return bind(c);
412393
}
413394

414-
public final <L, B> Either<L, Option<B>> traverseEither(F<A, Either<L, B>> f) {
415-
return map(a -> f.f(a).right().map(Option::some)).orSome(Either.right(none()));
395+
/**
396+
* Sequence the given option and collect the output on the right side of an either.
397+
*
398+
* @param option the given option
399+
* @param <R> the type of the right value
400+
* @param <B> the type of the left value
401+
* @return the either
402+
*/
403+
public static final <R, B> Either<Option<B>, R> sequenceEitherLeft(final Option<Either<B, R>> option) {
404+
return option.traverseEitherLeft(identity());
405+
}
406+
407+
/**
408+
* Sequence the given option and collect the output on the left side of an either.
409+
*
410+
* @param option the given option
411+
* @param <B> the type of the right value
412+
* @param <L> the type of the left value
413+
* @return the either
414+
*/
415+
public static final <L, B> Either<L, Option<B>> sequenceEitherRight(final Option<Either<L, B>> option) {
416+
return option.traverseEitherRight(identity());
417+
}
418+
419+
/**
420+
* Sequence the given option and collect the output as a function.
421+
*
422+
* @param option the given option
423+
* @param <C> the type of the input value
424+
* @param <B> the type of the output value
425+
* @return the either
426+
*/
427+
public static final <C, B> F<C, Option<B>> sequenceF(final Option<F<C, B>> option) {
428+
return option.traverseF(identity());
429+
}
430+
431+
/**
432+
* Sequence the given option and collect the output as an IO.
433+
*
434+
* @param option the given option
435+
* @param <B> the type of the IO value
436+
* @return the IO
437+
*/
438+
public static final <B> IO<Option<B>> sequenceIO(final Option<IO<B>> option) {
439+
return option.traverseIO(identity());
440+
}
441+
442+
/**
443+
* Sequence the given option and collect the output as an list.
444+
*
445+
* @param option the given option
446+
* @param <B> the type of the list value
447+
* @return the list
448+
*/
449+
public static final <B> List<Option<B>> sequenceList(final Option<List<B>> option) {
450+
return option.traverseList(identity());
416451
}
417452

418-
public final <B> IO<Option<B>> traverseIO(F<A, IO<B>> f) {
419-
return map(a -> IOFunctions.map(f.f(a), Option::some)).orSome(IOFunctions.lazy(Option::none));
453+
/**
454+
* Sequence the given option and collect the output as an option.
455+
*
456+
* @param option the given option
457+
* @param <B> the type of the option value
458+
* @return the option
459+
*/
460+
public static final <B> Option<Option<B>> sequenceOption(final Option<Option<B>> option) {
461+
return option.traverseOption(identity());
420462
}
421463

422-
public final <B> List<Option<B>> traverseList(F<A, List<B>> f) {
423-
return map(a -> f.f(a).map(Option::some)).orSome(List.list());
464+
/**
465+
* Sequence the given option and collect the output as a P1.
466+
*
467+
* @param option the given option
468+
* @param <B> the type of the P1 value
469+
* @return the P1
470+
*/
471+
public static final <B> P1<Option<B>> sequenceP1(final Option<P1<B>> option) {
472+
return option.traverseP1(identity());
424473
}
425474

426-
public final <B> Option<Option<B>> traverseOption(F<A, Option<B>> f) {
427-
return map(f);
475+
/**
476+
* Sequence the given option and collect the output as a seq.
477+
*
478+
* @param option the given option
479+
* @param <B> the type of the seq value
480+
* @return the seq
481+
*/
482+
public static final <B> Seq<Option<B>> sequenceSeq(final Option<Seq<B>> option) {
483+
return option.traverseSeq(identity());
428484
}
429485

430-
public final <B> Stream<Option<B>> traverseStream(F<A, Stream<B>> f) {
431-
return map(a -> f.f(a).map(Option::some)).orSome(Stream.nil());
486+
/**
487+
* Sequence the given option and collect the output as a set; use the given ord to order the set.
488+
*
489+
* @param ord the given ord
490+
* @param option the given option
491+
* @param <B> the type of the set value
492+
* @return the either
493+
*/
494+
public static final <B> Set<Option<B>> sequenceSet(final Ord<B> ord, final Option<Set<B>> option) {
495+
return option.traverseSet(ord, identity());
432496
}
433497

434-
public final <B> P1<Option<B>> traverseP1(F<A, P1<B>> f) {
435-
return map(a -> f.f(a).map(Option::some)).orSome(p(none()));
498+
/**
499+
* Sequence the given option and collect the output as a stream.
500+
*
501+
* @param option the given option
502+
* @param <B> the type of the stream value
503+
* @return the stream
504+
*/
505+
public static final <B> Stream<Option<B>> sequenceStream(final Option<Stream<B>> option) {
506+
return option.traverseStream(identity());
436507
}
437508

438-
public final <B> Seq<Option<B>> traverseSeq(F<A, Seq<B>> f) {
439-
return map(a -> f.f(a).map(Option::some)).orSome(Seq.empty());
509+
/**
510+
* Sequence the given option and collect the output as a trampoline.
511+
*
512+
* @param option the given trampoline
513+
* @param <B> the type of the stream value
514+
* @return the stream
515+
*/
516+
public static final <B> Trampoline<Option<B>> sequenceTrampoline(final Option<Trampoline<B>> option) {
517+
return option.traverseTrampoline(identity());
440518
}
441519

442-
public final <B> Set<Option<B>> traverseSet(Ord<B> ord, F<A, Set<B>> f) {
443-
Ord<Option<B>> optOrd = Ord.optionOrd(ord);
444-
return map(a -> f.f(a).map(optOrd, Option::some)).orSome(Set.empty(optOrd));
520+
/**
521+
* Sequence the given option and collect the output as a validation.
522+
*
523+
* @param option the given option
524+
* @param <E> the type of the failure value
525+
* @param <B> the type of the success value
526+
* @return the validation
527+
*/
528+
public static final <E, B> Validation<E, Option<B>> sequenceValidation(final Option<Validation<E, B>> option) {
529+
return option.traverseValidation(identity());
445530
}
446531

447-
public final <B> F2<Ord<B>, F<A, Set<B>>, Set<Option<B>>> traverseSet() {
448-
return this::traverseSet;
532+
/**
533+
* Traverse this option with the given function and collect the output on the left side of an either.
534+
*
535+
* @param f the given function
536+
* @param <R> the type of the left value
537+
* @param <B> the type of the right value
538+
* @return the either
539+
*/
540+
public final <R, B> Either<Option<B>, R> traverseEitherLeft(final F<A, Either<B, R>> f) {
541+
return option(
542+
left(none()),
543+
a -> f.f(a).left().map(Option::some));
449544
}
450545

451-
public final <E, B> Validation<E, Option<B>> traverseValidation(F<A, Validation<E, B>> f) {
452-
return map(a -> f.f(a).map(Option::some)).orSome(Validation.success(none()));
546+
/**
547+
* Traverse this option with the given function and collect the output on the right side of an either.
548+
*
549+
* @param f the given function
550+
* @param <L> the type of the left value
551+
* @param <B> the type of the right value
552+
* @return the either
553+
*/
554+
public final <L, B> Either<L, Option<B>> traverseEitherRight(final F<A, Either<L, B>> f) {
555+
return option(
556+
right(none()),
557+
a -> f.f(a).right().map(Option::some));
558+
}
559+
560+
/**
561+
* Traverse this option with the given function and collect the output as a function.
562+
*
563+
* @param f the given function
564+
* @param <C> the type of the input value
565+
* @param <B> the type of the output value
566+
* @return the function
567+
*/
568+
public final <C, B> F<C, Option<B>> traverseF(final F<A, F<C, B>> f) {
569+
return option(
570+
constant(none()),
571+
a -> andThen(f.f(a), Option::some));
572+
}
573+
574+
/**
575+
* Traverse this option with the given function and collect the output as an IO.
576+
*
577+
* @param f the given function
578+
* @param <B> the type of the IO value
579+
* @return the IO
580+
*/
581+
public final <B> IO<Option<B>> traverseIO(final F<A, IO<B>> f) {
582+
return option(
583+
IOFunctions.lazy(Option::none),
584+
a -> IOFunctions.map(f.f(a), Option::some));
585+
}
586+
587+
/**
588+
* Traverse this option with the given function and collect the output as a list.
589+
*
590+
* @param f the given function
591+
* @param <B> the type of the list value
592+
* @return the list
593+
*/
594+
public final <B> List<Option<B>> traverseList(final F<A, List<B>> f) {
595+
return option(
596+
List.single(none()),
597+
a -> f.f(a).map(Option::some));
598+
}
599+
600+
/**
601+
* Traverse this option with the given function and collect the output as an option.
602+
*
603+
* @param f the given function
604+
* @param <B> the type of the option value
605+
* @return the option
606+
*/
607+
public final <B> Option<Option<B>> traverseOption(final F<A, Option<B>> f) {
608+
return option(
609+
some(none()),
610+
a -> f.f(a).map(Option::some));
611+
}
612+
613+
/**
614+
* Traverse this option with the given function and collect the output as a P1.
615+
*
616+
* @param f the given function
617+
* @param <B> the type of the P1 value
618+
* @return the P1
619+
*/
620+
public final <B> P1<Option<B>> traverseP1(final F<A, P1<B>> f) {
621+
return option(
622+
p(none()),
623+
(F<A, P1<Option<B>>>) a -> f.f(a).map(Option::some));
624+
}
625+
626+
/**
627+
* Traverse this option with the given function and collect the output a seq.
628+
*
629+
* @param f the given function
630+
* @param <B> the type of the seq value
631+
* @return the seq
632+
*/
633+
public final <B> Seq<Option<B>> traverseSeq(final F<A, Seq<B>> f) {
634+
return option(
635+
Seq.single(none()),
636+
a -> f.f(a).map(Option::some));
637+
}
638+
639+
/**
640+
* Traverse this option with the given function and collect the output as a set; use the given ord to order the set.
641+
*
642+
* @param ord the given ord
643+
* @param f the given function
644+
* @param <B> the type of the set value
645+
* @return the set
646+
*/
647+
public final <B> Set<Option<B>> traverseSet(final Ord<B> ord, final F<A, Set<B>> f) {
648+
final Ord<Option<B>> ordOption = Ord.optionOrd(ord);
649+
return option(
650+
Set.single(ordOption, none()),
651+
a -> f.f(a).map(ordOption, Option::some));
652+
}
653+
654+
/**
655+
* Traverse this option with the given function and collect the output as a stream.
656+
*
657+
* @param f the given function
658+
* @param <B> the type of the stream value
659+
* @return the stream
660+
*/
661+
public final <B> Stream<Option<B>> traverseStream(final F<A, Stream<B>> f) {
662+
return option(
663+
Stream.single(none()),
664+
a -> f.f(a).map(Option::some));
665+
}
666+
667+
/**
668+
* Traverse this option with the given function and collect the output as a trampoline.
669+
*
670+
* @param f the given function
671+
* @param <B> the type of the trampoline value
672+
* @return the trampoline
673+
*/
674+
public final <B> Trampoline<Option<B>> traverseTrampoline(final F<A, Trampoline<B>> f) {
675+
return option(
676+
pure(none()),
677+
a -> f.f(a).map(Option::some));
678+
}
679+
680+
/**
681+
* Traverse this option with the given function and collect the output as a validation.
682+
*
683+
* @param f the given function
684+
* @param <E> the type of the failure value
685+
* @param <B> the type of the success value
686+
* @return the validation
687+
*/
688+
public final <E, B> Validation<E, Option<B>> traverseValidation(final F<A, Validation<E, B>> f) {
689+
return option(
690+
success(none()),
691+
a -> f.f(a).map(Option::some));
692+
}
693+
694+
public final <B> F2<Ord<B>, F<A, Set<B>>, Set<Option<B>>> traverseSet() {
695+
return this::traverseSet;
453696
}
454697

455698
/**

0 commit comments

Comments
 (0)