-
Notifications
You must be signed in to change notification settings - Fork 253
Optic instances for List and P2 #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
82e3773
14d7065
ec2c333
c515983
ba6ad5f
ab5acf2
9333f45
a3407f6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| package fj; | ||
|
|
||
| import static fj.Function.*; | ||
|
|
||
| import static fj.data.optic.PLens.pLens; | ||
| import fj.data.*; | ||
| import fj.data.optic.Lens; | ||
| import fj.data.optic.PLens; | ||
|
|
||
| /** | ||
| * A product-2. | ||
|
|
@@ -342,6 +344,34 @@ public static <A, B, C> F2<A, B, C> untuple(final F<P2<A, B>, C> f) { | |
| return (a, b) -> f.f(P.p(a, b)); | ||
| } | ||
|
|
||
| /** | ||
| * Polyomorphic lens targeted on _1. | ||
| */ | ||
| public static <A, B, C> PLens<P2<A, B>, P2<C, B>, A, C> _1pLens() { | ||
| return pLens(__1(), a -> p2 -> P.p(a, p2._2())); | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A dumb question: Where does the naming convention for
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no real convention here, I'm happy to change the name. I originally wanted
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for reference, the Monocle library use |
||
| /** | ||
| * Monomorphic lens targeted on _1. | ||
| */ | ||
| public static <A, B, C> Lens<P2<A, B>, A> _1Lens() { | ||
| return new Lens<>(_1pLens()); | ||
| } | ||
|
|
||
| /** | ||
| * Polyomorphic lens targeted on _2. | ||
| */ | ||
| public static <A, B, C> PLens<P2<A, B>, P2<A, C>, B, C> _2pLens() { | ||
| return pLens(__2(), b -> p2 -> P.p(p2._1(), b)); | ||
| } | ||
|
|
||
| /** | ||
| * Monomorphic lens targeted on _1. | ||
| */ | ||
| public static <A, B, C> Lens<P2<A, B>, B> _2Lens() { | ||
| return new Lens<>(_2pLens()); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return Show.p2Show(Show.<A>anyShow(), Show.<B>anyShow()).showS(this); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,11 +26,21 @@ | |
| import static fj.data.List.Buffer.*; | ||
| import static fj.data.Option.none; | ||
| import static fj.data.Option.some; | ||
| import static fj.data.optic.Optional.optional; | ||
| import static fj.data.optic.Prism.prism; | ||
| import static fj.data.vector.V.v; | ||
| import static fj.function.Booleans.not; | ||
| import static fj.Ordering.GT; | ||
| import static fj.Ord.intOrd; | ||
| import fj.Ordering; | ||
| import fj.control.Trampoline; | ||
| import fj.control.parallel.Promise; | ||
| import fj.control.parallel.Strategy; | ||
| import fj.data.optic.Optional; | ||
| import fj.data.optic.PTraversal; | ||
| import fj.data.optic.Prism; | ||
| import fj.data.optic.Traversal; | ||
| import fj.data.vector.V2; | ||
| import fj.function.Effect1; | ||
|
|
||
| import java.util.AbstractCollection; | ||
|
|
@@ -608,6 +618,119 @@ public <B> IO<List<B>> traverseIO(F<A, IO<B>> f) { | |
| ); | ||
| } | ||
|
|
||
| public <C, B> F<C, List<B>> traverseF(F<A, F<C, B>> f) { | ||
| return this.foldRight( | ||
| (a, acc) -> Function.bind(acc, | ||
| (bs) -> Function.<C, B, List<B>> compose(b -> bs.cons(b), f.f(a))), | ||
| Function.constant(List.<B> nil()) | ||
| ); | ||
| } | ||
|
|
||
| public <B> Trampoline<List<B>> traverseTrampoline(final F<A, Trampoline<B>> f) { | ||
| return foldRight( | ||
| (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), | ||
| Trampoline.pure(List.<B> nil())); | ||
| } | ||
|
|
||
| public <B> Promise<List<B>> traversePromise(final F<A, Promise<B>> f) { | ||
| return foldRight( | ||
| (a, acc) -> f.f(a).bind(b -> acc.fmap(bs -> bs.cons(b))), | ||
| Promise.promise(Strategy.idStrategy(), p(List.<B> nil()))); | ||
| } | ||
|
|
||
| public <B> List<List<B>> traverseList(final F<A, List<B>> f) { | ||
| return foldRight( | ||
| (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), | ||
| List.single(List.<B> nil())); | ||
| } | ||
|
|
||
| public <E, B> Validation<E, List<B>> traverseValidation(final F<A, Validation<E, B>> f) { | ||
| return foldRight( | ||
| (a, acc) -> f.f(a).bind(b -> acc.map(bs -> bs.cons(b))), | ||
| Validation.success(List.<B> nil())); | ||
| } | ||
|
|
||
| public <B> V2<List<B>> traverseV2(final F<A, V2<B>> f) { | ||
| return foldRight( | ||
| (a, acc) -> acc.apply(f.f(a).<F<List<B>, List<B>>> map(e -> es -> es.cons(e))), | ||
| v(List.<B> nil(), List.<B> nil())); | ||
| } | ||
|
|
||
| /** | ||
| * polymorphic traversal | ||
| */ | ||
| public static <A, B> PTraversal<List<A>, List<B>, A, B> _pTraversal() { | ||
| return new PTraversal<List<A>, List<B>, A, B>() { | ||
|
|
||
| @Override | ||
| public <C> F<List<A>, F<C, List<B>>> modifyFunctionF(F<A, F<C, B>> f) { | ||
| return l -> l.traverseF(f); | ||
| } | ||
|
|
||
| @Override | ||
| public <L> F<List<A>, Either<L, List<B>>> modifyEitherF(F<A, Either<L, B>> f) { | ||
| return l -> l.traverseEither(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, IO<List<B>>> modifyIOF(F<A, IO<B>> f) { | ||
| return l -> l.traverseIO(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, Trampoline<List<B>>> modifyTrampolineF(F<A, Trampoline<B>> f) { | ||
| return l -> l.traverseTrampoline(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, Promise<List<B>>> modifyPromiseF(F<A, Promise<B>> f) { | ||
| return l -> l.traversePromise(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, List<List<B>>> modifyListF(F<A, List<B>> f) { | ||
| return l -> l.traverseList(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, Option<List<B>>> modifyOptionF(F<A, Option<B>> f) { | ||
| return l -> l.traverseOption(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, Stream<List<B>>> modifyStreamF(F<A, Stream<B>> f) { | ||
| return l -> l.traverseStream(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, P1<List<B>>> modifyP1F(F<A, P1<B>> f) { | ||
| return l -> l.traverseP1(f); | ||
| } | ||
|
|
||
| @Override | ||
| public <E> F<List<A>, Validation<E, List<B>>> modifyValidationF(F<A, Validation<E, B>> f) { | ||
| return l -> l.traverseValidation(f); | ||
| } | ||
|
|
||
| @Override | ||
| public F<List<A>, V2<List<B>>> modifyV2F(F<A, V2<B>> f) { | ||
| return l -> l.traverseV2(f); | ||
| } | ||
|
|
||
| @Override | ||
| public <M> F<List<A>, M> foldMap(Monoid<M> monoid, F<A, M> f) { | ||
| return l -> monoid.sumLeft(l.map(f)); | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| /** | ||
| * monomorphic traversal | ||
| */ | ||
| public static <A> Traversal<List<A>, A> _traversal() { | ||
| return new Traversal<>(_pTraversal()); | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I prefer However, take note that I am a beginner user of lens. This would mean the Your thoughts?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lens is one kind of optics, Traversal is another, so lensTraversal would be confusing. so for
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, I was using lens as the package as a whole, like the Haskell lens package (e.g. Control.Lens.Iso). For others learning about this information, there is lots of useful info on the Github lens library page, https://github.com/ekmett/lens. |
||
| /** | ||
| * Performs function application within a list (applicative functor pattern). | ||
| * | ||
|
|
@@ -1054,6 +1177,13 @@ public final List<A> nub(final Ord<A> o) { | |
| return sort(o).group(o.equal()).map(List.<A>head_()); | ||
| } | ||
|
|
||
| /** | ||
| * Optional targeted on Cons head. | ||
| */ | ||
| public static <A> Optional<List<A>, A> _head() { | ||
| return optional(l -> l.toOption(), a -> l -> l.<List<A>> list(l, constant(cons_(a)))); | ||
| } | ||
|
|
||
| /** | ||
| * First-class head function. | ||
| * | ||
|
|
@@ -1063,6 +1193,14 @@ public static <A> F<List<A>, A> head_() { | |
| return list -> list.head(); | ||
| } | ||
|
|
||
| /** | ||
| * Optional targeted on Cons tail. | ||
| */ | ||
| public static <A> Optional<List<A>, List<A>> _tail() { | ||
| return optional(l -> l.<Option<List<A>>> list(none(), h -> tail -> some(tail)), | ||
| tail -> l -> l.list(l, h -> constant(cons(h, tail)))); | ||
| } | ||
|
|
||
| /** | ||
| * First-class tail function. | ||
| * | ||
|
|
@@ -1434,6 +1572,13 @@ public static <A> List<A> nil() { | |
| return (Nil<A>) Nil.INSTANCE; | ||
| } | ||
|
|
||
| /** | ||
| * Nil prism | ||
| */ | ||
| public static <A> Prism<List<A>, Unit> _nil() { | ||
| return prism(l -> l.isEmpty() ? some(unit()) : none(), constant(nil())); | ||
| } | ||
|
|
||
| /** | ||
| * Returns a function that prepends (cons) an element to a list to produce a new list. | ||
| * | ||
|
|
@@ -1443,6 +1588,13 @@ public static <A> F<A, F<List<A>, List<A>>> cons() { | |
| return a -> tail -> cons(a, tail); | ||
| } | ||
|
|
||
| /** | ||
| * Cons prism | ||
| */ | ||
| public static <A> Prism<List<A>, P2<A, List<A>>> _cons() { | ||
| return prism(l -> l.<Option<P2<A, List<A>>>> list(none(), h -> tail -> some(P.p(h, tail))), c -> cons(c._1(), c._2())); | ||
| } | ||
|
|
||
| public static <A> F2<A, List<A>, List<A>> cons_() { | ||
| return (a, listA) -> cons(a, listA); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm concerned about putting optic instances in the same classes. The reason is that it will cause cyclic references between packages/classes (e.g. PLens depends on List and List depends on PLens). In Monocle there is no such problem: optic instances are located in monocle.std package. What if we use the same strategy and create fj.data.optic.std package?
Also, what do you think about creating a new artifact functionaljava-lens with all fj.data.optic stuff in it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is a valid concern. However there is already many cyclic packages references in fj (eg. Monoid<->Stream). Scalaz solve cyclic references by putting all in a single package. For those reasons I considered all of fj to be a single 'package'.
I can move optic instances into their own package/artifact, the downside I can see is that it will be harder to find them. pro is that it will address @mperry concern about having a clear distinction for optics 'factory methods'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Monoid and Stream are central entities in functional programming, while lenses are not (IMO). Lenses are great, but I think optic methods in "standard" classes will confuse people that are new to functional programming.
Regarding Scalaz: putting everything into a single package led to a huge jar (10 MB) which is not good at all. I would like not to repeat this mistake in functionaljava.
Anyway, this is just my personal point view, so I would like to hear other opinions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lenses (optics) are way more important to functional programming, in a practical regard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to see them in their own package, but don't see the need for a separate artifact.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another reason is that instances for List regarding things like Equal, Show, etc. are in those classes, rather than List.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mperry so... do you suggest to put optics instances in Prism, Lens, Ptraversal and the like...? I think this could be practical...
if they are isolated in their own package, those 'orphan' optics that will be harder to find which will lower their practicality.