Skip to content

Commit a64af56

Browse files
committed
Updating index.md with latest README contents
1 parent 61b2aad commit a64af56

File tree

1 file changed

+111
-19
lines changed

1 file changed

+111
-19
lines changed

index.md

Lines changed: 111 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
λ
22
======
3-
[![Build Status](https://travis-ci.org/palatable/lambda.svg)](https://travis-ci.org/palatable/lambda)
3+
[![Build Status](https://img.shields.io/travis/palatable/lambda/master.svg)](https://travis-ci.org/palatable/lambda)
44
[![Lambda](https://img.shields.io/maven-central/v/com.jnape.palatable/lambda.svg)](http://search.maven.org/#search%7Cga%7C1%7Ccom.jnape.palatable.lambda)
55

6-
Functional patterns for Java 8
6+
Functional patterns for Java
77

88
#### Table of Contents
99

@@ -16,9 +16,11 @@ Functional patterns for Java 8
1616
- [Bifunctors](#bifunctors)
1717
- [Profunctors](#profunctors)
1818
- [Applicatives](#applicatives)
19+
- [Monads](#monads)
1920
- [Traversables](#traversables)
2021
- [ADTs](#adts)
21-
- [HLists](#hlists)
22+
- [Maybe](#maybe)
23+
- [HList](#hlist)
2224
- [Tuples](#tuples)
2325
- [HMaps](#hmaps)
2426
- [CoProducts](#coproducts)
@@ -55,14 +57,14 @@ Add the following dependency to your:
5557
<dependency>
5658
<groupId>com.jnape.palatable</groupId>
5759
<artifactId>lambda</artifactId>
58-
<version>1.6.3</version>
60+
<version>3.1.0</version>
5961
</dependency>
6062
```
6163

6264
`build.gradle` ([Gradle](https://docs.gradle.org/current/userguide/dependency_management.html)):
6365

6466
```gradle
65-
compile group: 'com.jnape.palatable', name: 'lambda', version: '1.6.3'
67+
compile group: 'com.jnape.palatable', name: 'lambda', version: '3.1.0'
6668
```
6769

6870
<a name="examples">Examples</a>
@@ -335,6 +337,41 @@ Examples of applicative functors include:
335337

336338
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.
337339

340+
### <a name="monads">Monads</a>
341+
342+
Monads are applicative functors that additionally support a chaining operation, `flatMap :: (a -> f b) -> f a -> f b`: a function from the functor's parameter to a new instance of the same functor over a potentially different parameter. Because the function passed to `flatMap` can return a different instance of the same functor, functors can take advantage of multiple constructions that yield different functorial operations, like short-circuiting, as in the following example using `Either`:
343+
344+
```Java
345+
class Person {
346+
Optional<Occupation> occupation() {
347+
return Optional.empty();
348+
}
349+
}
350+
351+
class Occupation {
352+
}
353+
354+
public static void main(String[] args) {
355+
Fn1<String, Either<String, Integer>> parseId = str -> Either.trying(() -> Integer.parseInt(str), __ -> str + " is not a valid id");
356+
357+
Map<Integer, Person> database = new HashMap<>();
358+
Fn1<Integer, Either<String, Person>> lookupById = id -> Either.fromOptional(Optional.ofNullable(database.get(id)),
359+
() -> "No person found for id " + id);
360+
Fn1<Person, Either<String, Occupation>> getOccupation = p -> Either.fromOptional(p.occupation(), () -> "Person was unemployed");
361+
362+
Either<String, Occupation> occupationOrError =
363+
parseId.apply("12") // Either<String, Integer>
364+
.flatMap(lookupById) // Either<String, Person>
365+
.flatMap(getOccupation); // Either<String, Occupation>
366+
}
367+
```
368+
369+
In the previous example, if any of `parseId`, `lookupById`, or `getOccupation` fail, no further `flatMap` computations can succeed, so the result short-circuits to the first `left` value that is returned. This is completely predictable from the type signature of `Monad` and `Either`: `Either<L, R>` is a `Monad<R>`, so the single arity `flatMap` can have nothing to map in the case where there is no `R` value. With experience, it generally becomes quickly clear what the logical behavior of `flatMap` *must* be given the type signatures.
370+
371+
That's it. Monads are neither [elephants](http://james-iry.blogspot.com/2007/09/monads-are-elephants-part-1.html) nor are they [burritos](https://blog.plover.com/prog/burritos.html); they're simply types that support a) the ability to lift a value into them, and b) a chaining function `flatMap :: (a -> f b) -> f a -> f b` that can potentially return different instances of the same monad. If a type can do those two things (and obeys [the laws](https://wiki.haskell.org/Monad_laws)), it is a monad.
372+
373+
Further, if a type is a monad, it is necessarily an `Applicative`, which makes it necessarily a `Functor`, so *lambda* enforces this tautology via a hierarchical constraint.
374+
338375
### <a name="traversables">Traversables</a>
339376

340377
Traversable functors -- functors that can be "traversed from left to right" -- are implemented via the `Traversable` interface.
@@ -407,8 +444,7 @@ Examples of traversable functors include:
407444
- `Choice*`
408445
- `Either`
409446
- `Const` and `Identity`
410-
- `TraversableIterable` for wrapping `Iterable` in an instance of `Traversable`
411-
- `TraversableOptional` for wrapping `Optional` in an instance of `Traversable`
447+
- `LambdaIterable` for wrapping `Iterable` in an instance of `Traversable`
412448

413449
In addition to implementing `fmap` from `Functor`, implementing a traversable functor involves providing an implementation of `traverse`.
414450

@@ -419,6 +455,56 @@ As always, there are [some laws](https://hackage.haskell.org/package/base-4.9.1.
419455

420456
Lambda also supports a few first-class [algebraic data types](https://www.wikiwand.com/en/Algebraic_data_type).
421457

458+
### <a name="maybe">Maybe</a>
459+
460+
`Maybe` is the _lambda_ analog to `java.util.Optional`. It behaves in much of the same way as `j.u.Optional`, except that it quite intentionally does not support the inherently unsafe `j.u.Optional#get`.
461+
462+
```Java
463+
Maybe<Integer> maybeInt = Maybe.just(1); // Just 1
464+
Maybe<String> maybeString = Maybe.nothing(); // Nothing
465+
```
466+
467+
Also, because it's a _lambda_ type, it takes advantage of the full functor hierarchy, as well as some helpful conversion functions:
468+
469+
```Java
470+
Maybe<String> just = Maybe.maybe("string"); // Just "string"
471+
Maybe<String> nothing = Maybe.maybe(null); // Nothing
472+
473+
Maybe<Integer> maybeX = Maybe.just(1);
474+
Maybe<Integer> maybeY = Maybe.just(2);
475+
476+
maybeY.zip(maybeX.fmap(x -> y -> x + y)); // Just 3
477+
maybeY.zip(nothing()); // Nothing
478+
Maybe.<Integer>nothing().zip(maybeX.fmap(x -> y -> x + y)); // Nothing
479+
480+
Either<String, Integer> right = maybeX.toEither(() -> "was empty"); // Right 1
481+
Either<String, Integer> left = Maybe.<Integer>nothing().toEither(() -> "was empty"); // Left "was empty"
482+
483+
Maybe.fromEither(right); // Just 1
484+
Maybe.fromEither(left); // Nothing
485+
```
486+
487+
Finally, for compatibility purposes, `Maybe` and `j.u.Optional` can be trivially converted back and forth:
488+
489+
```Java
490+
Maybe<Integer> just1 = Maybe.just(1); // Just 1
491+
Optional<Integer> present1 = just1.toOptional(); // Optional.of(1)
492+
493+
Optional<String> empty = Optional.empty(); // Optional.empty()
494+
Maybe<String> nothing = Maybe.fromOptional(empty); // Nothing
495+
```
496+
497+
***Note***: One compatibility difference between `j.u.Optional` and `Maybe` is how `map`/`fmap` behave regarding functions that return `null`: `j.u.Optional` re-wraps `null` results from `map` operations in another `j.u.Optional`, whereas `Maybe` considers this to be an error, and throws an exception. The reason `Maybe` throws in this case is because `fmap` is not an operation to be called speculatively, and so any function that returns `null` in the context of an `fmap` operation is considered to be erroneous. Instead of calling `fmap` with a function that might return `null`, the function result should be wrapped in a `Maybe` and `flatMap` should be used, as illustrated in the following example:
498+
499+
```Java
500+
Function<Integer, Object> nullResultFn = __ -> null;
501+
502+
Optional.of(1).map(nullResultFn); // Optional.empty()
503+
Maybe.just(1).fmap(nullResultFn); // throws NullPointerException
504+
505+
Maybe.just(1).flatMap(nullResultFn.andThen(Maybe::maybe)); // Nothing
506+
```
507+
422508
### <a name="hlists">Heterogeneous Lists (HLists)</a>
423509
424510
HLists are type-safe heterogeneous lists, meaning they can store elements of different types in the same list while facilitating certain type-safe interactions.
@@ -439,28 +525,34 @@ HNil nil = hList.tail().tail();
439525

440526
One of the primary downsides to using `HList`s in Java is how quickly the type signature grows.
441527

442-
To address this, tuples in lambda are specializations of `HList`s up to 5 elements deep, with added support for index-based accessor methods.
528+
To address this, tuples in lambda are specializations of `HList`s up to 8 elements deep, with added support for index-based accessor methods.
443529

444530
```Java
445531
HNil nil = HList.nil();
446-
SingletonHList<Integer> singleton = nil.cons(5);
447-
Tuple2<Integer, Integer> tuple2 = singleton.cons(4);
448-
Tuple3<Integer, Integer, Integer> tuple3 = tuple2.cons(3);
449-
Tuple4<Integer, Integer, Integer, Integer> tuple4 = tuple3.cons(2);
450-
Tuple5<Integer, Integer, Integer, Integer, Integer> tuple5 = tuple4.cons(1);
532+
SingletonHList<Integer> singleton = nil.cons(8);
533+
Tuple2<Integer, Integer> tuple2 = singleton.cons(7);
534+
Tuple3<Integer, Integer, Integer> tuple3 = tuple2.cons(6);
535+
Tuple4<Integer, Integer, Integer, Integer> tuple4 = tuple3.cons(5);
536+
Tuple5<Integer, Integer, Integer, Integer, Integer> tuple5 = tuple4.cons(4);
537+
Tuple6<Integer, Integer, Integer, Integer, Integer, Integer> tuple6 = tuple5.cons(3);
538+
Tuple7<Integer, Integer, Integer, Integer, Integer, Integer, Integer> tuple7 = tuple6.cons(2);
539+
Tuple8<Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer> tuple8 = tuple7.cons(1);
451540

452-
System.out.println(tuple2._1()); // prints 4
453-
System.out.println(tuple5._5()); // prints 5
541+
System.out.println(tuple2._1()); // prints 7
542+
System.out.println(tuple8._8()); // prints 8
454543
```
455544

456-
Additionally, `HList` provides convenience static factory methods for directly constructing lists of up to 5 elements:
545+
Additionally, `HList` provides convenience static factory methods for directly constructing lists of up to 8 elements:
457546

458547
```Java
459548
SingletonHList<Integer> singleton = HList.singletonHList(1);
460549
Tuple2<Integer, Integer> tuple2 = HList.tuple(1, 2);
461550
Tuple3<Integer, Integer, Integer> tuple3 = HList.tuple(1, 2, 3);
462551
Tuple4<Integer, Integer, Integer, Integer> tuple4 = HList.tuple(1, 2, 3, 4);
463552
Tuple5<Integer, Integer, Integer, Integer, Integer> tuple5 = HList.tuple(1, 2, 3, 4, 5);
553+
Tuple6<Integer, Integer, Integer, Integer, Integer, Integer> tuple6 = HList.tuple(1, 2, 3, 4, 5, 6);
554+
Tuple7<Integer, Integer, Integer, Integer, Integer, Integer, Integer> tuple7 = HList.tuple(1, 2, 3, 4, 5, 6, 7);
555+
Tuple8<Integer, Integer, Integer, Integer, Integer, Integer, Integer, Integer> tuple8 = HList.tuple(1, 2, 3, 4, 5, 6, 7, 8);
464556
```
465557

466558
`Index` can be used for type-safe retrieval and updating of elements at specific indexes:
@@ -508,7 +600,7 @@ HMap hmap = HMap.hMap(stringKey, "string value",
508600
Optional<String> stringValue = hmap.get(stringKey); // Optional["string value"]
509601
Optional<Integer> intValue = hmap.get(intKey); // Optional[1]
510602
Optional<Integer> anotherIntValue = hmap.get(anotherIntKey); // Optional.empty
511-
```
603+
```
512604

513605
### <a name="coproducts">CoProducts</a>
514606

@@ -537,7 +629,7 @@ CoProduct2<String, Integer, ?> coProduct2 = Choice2.a("string");
537629
CoProduct3<String, Integer, Character, ?> coProduct3 = coProduct2.diverge(); // still just the coProduct2 value, adapted to the coProduct3 shape
538630
```
539631

540-
There are `CoProduct` and `Choice` specializations for type unions of up to 5 different types: `CoProduct2` through `CoProduct5`, and `Choice2` through `Choice5`, respectively.
632+
There are `CoProduct` and `Choice` specializations for type unions of up to 8 different types: `CoProduct2` through `CoProduct8`, and `Choice2` through `Choice8`, respectively.
541633

542634
### <a name="either">Either</a>
543635

@@ -647,4 +739,4 @@ Unfortunately, due to Java's type hierarchy and inheritance inconsistencies, thi
647739
<a name="license">License</a>
648740
-------
649741

650-
_lambda_ is part of [palatable](http://www.github.com/palatable), which is distributed under [The MIT License](http://choosealicense.com/licenses/mit/).
742+
_lambda_ is part of [palatable](http://www.github.com/palatable), which is distributed under [The MIT License](http://choosealicense.com/licenses/mit/).

0 commit comments

Comments
 (0)