Skip to content

Commit efa0a22

Browse files
authored
Updating from README
1 parent 74fd309 commit efa0a22

File tree

1 file changed

+184
-20
lines changed

1 file changed

+184
-20
lines changed

index.md

Lines changed: 184 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,21 @@ Although the library is currently (very) small, these values should always be th
4848
------------
4949

5050
Add the following dependency to your:
51-
51+
5252
`pom.xml` ([Maven](https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)):
53-
53+
5454
```xml
5555
<dependency>
5656
<groupId>com.jnape.palatable</groupId>
5757
<artifactId>lambda</artifactId>
58-
<version>1.6.0</version>
58+
<version>1.6.1</version>
5959
</dependency>
6060
```
61-
61+
6262
`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):
63-
63+
6464
```gradle
65-
compile group: 'com.jnape.palatable', name: 'lambda', version: '1.6.0'
65+
compile group: 'com.jnape.palatable', name: 'lambda', version: '1.6.1'
6666
```
6767

6868
<a name="examples">Examples</a>
@@ -149,7 +149,13 @@ Check out the [tests](https://github.com/palatable/lambda/tree/master/src/test/j
149149
----
150150

151151
[Semigroups](https://en.wikipedia.org/wiki/Semigroup) are supported via `Semigroup<A>`, a subtype of `Fn2<A,A,A>`, and add left and right folds over an `Iterable<A>`.
152-
152+
153+
```Java
154+
Semigroup<Integer> add = (augend, addend) -> augend + addend;
155+
add.apply(1, 2); //-> 3
156+
add.foldLeft(0, asList(1, 2, 3)); //-> 6
157+
```
158+
153159
Lambda ships some default logical semigroups for lambda types and core JDK types. Common examples are:
154160

155161
- `AddAll` for concatenating two `Collection`s
@@ -161,7 +167,14 @@ Check out the [semigroup](https://palatable.github.io/lambda/javadoc/com/jnape/p
161167
<a name="monoids">Monoids</a>
162168
----
163169

164-
[Monoids](https://en.wikipedia.org/wiki/Monoid) are supported via `Monoid<A>`, a subtype of `Semigroup<A>` with an `A #identity()` method, and add left and right reduces over an `Iterable<A>`.
170+
[Monoids](https://en.wikipedia.org/wiki/Monoid) are supported via `Monoid<A>`, a subtype of `Semigroup<A>` with an `A #identity()` method, and add left and right reduces over an `Iterable<A>`, as well as `foldMap`.
171+
172+
```Java
173+
Monoid<Integer> multiply = monoid((x, y) -> x * y, 1);
174+
multiple.reduceLeft(emptyList()); //-> 1
175+
multiply.reduceLeft(asList(1, 2, 3)); //-> 6
176+
multiply.foldMap(Integer::parseInt, asList("1", "2", "3")); //-> also 6
177+
```
165178

166179
Some commonly used lambda monoid implementations include:
167180

@@ -179,6 +192,29 @@ Check out the [monoid](https://palatable.github.io/lambda/javadoc/com/jnape/pala
179192

180193
Functors are implemented via the `Functor` interface, and are sub-typed by every function type that lambda exports, as well as many of the [ADTs](#adts).
181194

195+
```Java
196+
public final class Slot<A> implements Functor<A, Slot> {
197+
private final A a;
198+
199+
public Slot(A a) {
200+
this.a = a;
201+
}
202+
203+
public A getA() {
204+
return a;
205+
}
206+
207+
@Override
208+
public <B> Slot<B> fmap(Function<? super A, ? extends B> fn) {
209+
return new Slot<>(fn.apply(a));
210+
}
211+
}
212+
213+
Slot<Integer> intSlot = new Slot<>(1);
214+
Slot<String> stringSlot = intSlot.fmap(x -> "number: " + x);
215+
stringSlot.getA(); //-> "number: 1"
216+
```
217+
182218
Examples of functors include:
183219

184220
- `Fn*`, `Semigroup`, and `Monoid`
@@ -194,6 +230,37 @@ Implementing `Functor` is as simple as providing a definition for the covariant
194230

195231
Bifunctors -- functors that support two parameters that can be covariantly mapped over -- are implemented via the `Bifunctor` interface.
196232

233+
```Java
234+
public final class Pair<A, B> implements Bifunctor<A, B, Pair> {
235+
private final A a;
236+
private final B b;
237+
238+
public Pair(A a, B b) {
239+
this.a = a;
240+
this.b = b;
241+
}
242+
243+
public A getA() {
244+
return a;
245+
}
246+
247+
public B getB() {
248+
return b;
249+
}
250+
251+
@Override
252+
public <C, D> Pair<C, D> biMap(Function<? super A, ? extends C> lFn,
253+
Function<? super B, ? extends D> rFn) {
254+
return new Pair<>(lFn.apply(a), rFn.apply(b));
255+
}
256+
}
257+
258+
Pair<String,Integer> stringIntPair = new Pair<>("str", 1);
259+
Pair<Integer, Boolean> intBooleanPair = stringIntPair.biMap(String::length, x -> x % 2 == 0);
260+
intBooleanPair.getA(); //-> 3
261+
intBooleanPair.getB(); //-> false
262+
```
263+
197264
Examples of bifunctors include:
198265

199266
- `Tuple*`
@@ -206,18 +273,57 @@ Implementing `Bifunctor` requires implementing *either* `biMapL` and `biMapR` *o
206273
### <a name="profunctors">Profunctors</a>
207274

208275
Profunctors -- functors that support one parameter that can be mapped over contravariantly, and a second parameter that can be mapped over covariantly -- are implemented via the `Profunctor` interface.
209-
210-
Examples of profunctors include:
211-
212-
- `Fn*`
213-
- `Lens`
276+
277+
```Java
278+
Fn1<Integer, Integer> add2 = (x) -> x + 2;
279+
add2.<String, String>diMap(Integer::parseInt, Object::toString).apply("1"); //-> "3"
280+
```
281+
282+
Examples of profunctors include:
283+
284+
- `Fn*`
285+
- `Lens`
214286

215287
Implementing `Profunctor` requires implementing *either* `diMapL` and `diMapR` *or* `diMap`. As with `Functor` and `Bifunctor`, there are [some laws](https://hackage.haskell.org/package/profunctors-5.2/docs/Data-Profunctor.html) that well behaved instances of `Profunctor` should adhere to.
216288

217289
### <a name="applicatives">Applicatives</a>
218290

219291
Applicative functors -- functors that can be applied together with a 2-arity or higher function -- are implemented via the `Applicative` interface.
220-
292+
293+
```Java
294+
public final class Slot<A> implements Applicative<A, Slot> {
295+
private final A a;
296+
297+
public Slot(A a) {
298+
this.a = a;
299+
}
300+
301+
public A getA() {
302+
return a;
303+
}
304+
305+
@Override
306+
public <B> Slot<B> fmap(Function<? super A, ? extends B> fn) {
307+
return pure(fn.apply(a));
308+
}
309+
310+
@Override
311+
public <B> Slot<B> pure(B b) {
312+
return new Slot<>(b);
313+
}
314+
315+
@Override
316+
public <B> Slot<B> zip(Applicative<Function<? super A, ? extends B>, Slot> appFn) {
317+
return pure(appFn.<Slot<Function<? super A, ? extends B>>>coerce().getA().apply(getA()));
318+
}
319+
}
320+
321+
Fn2<Integer, Integer, Integer> add = (x, y) -> x + y;
322+
Slot<Integer> x = new Slot<>(1);
323+
Slot<Integer> y = new Slot<>(2);
324+
Slot<Integer> z = y.zip(x.fmap(add)); //-> Slot{a=3}
325+
```
326+
221327
Examples of applicative functors include:
222328

223329
- `Fn*`, `Semigroup`, and `Monoid`
@@ -227,16 +333,74 @@ Examples of applicative functors include:
227333
- `Const`, `Identity`, and `Compose`
228334
- `Lens`
229335

230-
In addition to implementing `fmap` from `Functor`, implementing an applicative functor involves providing two methods: `pure`, a method that lifts a value into the functor; and `zip`, a method that applies a lifted function to a lifted value, returning a new lifted value. As usual, there are [some laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Applicative.html) that should be adhered to.
231-
232-
For example, imagine we have an `Fn2<String,String,String>` we'll call `join` that simply joins two strings. If we wanted to join the `String`s wrapped inside two `Either<Integer,String>` instances, without `Applicative`, we would at best only be able to `fmap` one while `fmap`ping the other, resulting in an `Either<Integer, Either<Integer,String>>`.
233-
234-
With `Applicative`, however, we can `fmap(join)` the first `Either<Integer String>`, resulting in an `Either<Integer, Fn1<String, String>>`, and then `zip` the second `Either<Integer, String>`, producing another `Either<Integer, String>`. In this way, `Applicative` can be thought of as facilitating `fmap`ping a functor with a multi-arity function.
336+
In addition to implementing `fmap` from `Functor`, implementing an applicative functor involves providing two methods: `pure`, a method that lifts a value into the functor; and `zip`, a method that applies a lifted function to a lifted value, returning a new lifted value. As usual, there are [some laws](https://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Applicative.html) that should be adhered to.
235337

236338
### <a name="traversables">Traversables</a>
237339

238340
Traversable functors -- functors that can be "traversed from left to right" -- are implemented via the `Traversable` interface.
239341

342+
```Java
343+
public abstract class Maybe<A> implements Traversable<A, Maybe> {
344+
private Maybe() {
345+
}
346+
347+
@Override
348+
public abstract <B, App extends Applicative> Applicative<Maybe<B>, App> traverse(
349+
Function<? super A, ? extends Applicative<B, App>> fn,
350+
Function<? super Traversable<B, Maybe>, ? extends Applicative<? extends Traversable<B, Maybe>, App>> pure);
351+
352+
@Override
353+
public abstract <B> Maybe<B> fmap(Function<? super A, ? extends B> fn);
354+
355+
private static final class Just<A> extends Maybe<A> {
356+
private final A a;
357+
358+
private Just(A a) {
359+
this.a = a;
360+
}
361+
362+
@Override
363+
public <B, App extends Applicative> Applicative<Maybe<B>, App> traverse(
364+
Function<? super A, ? extends Applicative<B, App>> fn,
365+
Function<? super Traversable<B, Maybe>, ? extends Applicative<? extends Traversable<B, Maybe>, App>> pure) {
366+
return fn.apply(a).fmap(Just::new);
367+
}
368+
369+
@Override
370+
public <B> Maybe<B> fmap(Function<? super A, ? extends B> fn) {
371+
return new Just<>(fn.apply(a));
372+
}
373+
}
374+
375+
private static final class Nothing<A> extends Maybe<A> {
376+
@Override
377+
@SuppressWarnings("unchecked")
378+
public <B, App extends Applicative> Applicative<Maybe<B>, App> traverse(
379+
Function<? super A, ? extends Applicative<B, App>> fn,
380+
Function<? super Traversable<B, Maybe>, ? extends Applicative<? extends Traversable<B, Maybe>, App>> pure) {
381+
return pure.apply((Maybe<B>) this).fmap(x -> (Maybe<B>) x);
382+
}
383+
384+
@Override
385+
@SuppressWarnings("unchecked")
386+
public <B> Maybe<B> fmap(Function<? super A, ? extends B> fn) {
387+
return (Maybe<B>) this;
388+
}
389+
}
390+
}
391+
392+
Maybe<Integer> just1 = Maybe.just(1);
393+
Maybe<Integer> nothing = Maybe.nothing();
394+
395+
Either<String, Maybe<Integer>> traversedJust = just1.traverse(x -> right(x + 1), empty -> left("empty"))
396+
.fmap(x -> (Maybe<Integer>) x)
397+
.coerce(); //-> Right(Just(2))
398+
399+
Either<String, Maybe<Integer>> traversedNothing = nothing.traverse(x -> right(x + 1), empty -> left("empty"))
400+
.fmap(x -> (Maybe<Integer>) x)
401+
.coerce(); //-> Left("empty")
402+
```
403+
240404
Examples of traversable functors include:
241405

242406
- `SingletonHList` and `Tuple*`
@@ -367,7 +531,7 @@ Integer result = string.<Integer>match(String::length, identity(), Character::ch
367531
```
368532

369533
Additionally, because a `CoProduct2<A, B>` guarantees a subset of a `CoProduct3<A, B, C>`, the `diverge` method exists between `CoProduct` types of single magnitude differences to make it easy to use a more convergent `CoProduct` where a more divergent `CoProduct` is expected:
370-
534+
371535
```Java
372536
CoProduct2<String, Integer> coProduct2 = Choice2.a("string");
373537
CoProduct3<String, Integer, Character> coProduct3 = coProduct2.diverge(); // still just the coProduct2 value, adapted to the coProduct3 shape

0 commit comments

Comments
 (0)