Skip to content

Commit 66ff9bf

Browse files
committed
Chapter 9 partial
1 parent 1c89b19 commit 66ff9bf

31 files changed

Lines changed: 1475 additions & 519 deletions

File tree

fpinjava-parent/build.gradle

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@ version = '1.0'
22
apply plugin: 'java'
33
apply plugin: 'eclipse'
44
apply plugin: 'idea'
5-
sourceCompatibility = 1.8
6-
targetCompatibility = 1.8
75

86
subprojects {
9-
sourceCompatibility = 1.8
107
apply plugin: 'java'
118
apply plugin: 'eclipse'
129
apply plugin: 'idea'
13-
sourceCompatibility = 1.8
14-
targetCompatibility = 1.8
1510

1611
repositories {
1712
mavenCentral()
@@ -165,6 +160,18 @@ project(':fpinjava-functionalparallelism-solutions') {
165160

166161
dependencies {
167162
compile project(':fpinjava-common')
163+
compile group: 'org.functionaljava', name: 'functionaljava-java8', version: '4.3'
164+
testCompile group: 'junit', name: 'junit', version: '4.+'
165+
testCompile group: 'com.pholser', name: 'junit-quickcheck-core', version: '0.5-alpha-1'
166+
testCompile group: 'com.pholser', name: 'junit-quickcheck-generators', version: '0.5-alpha-1'
167+
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
168+
}
169+
}
170+
171+
project(':fpinjava-test') {
172+
173+
dependencies {
174+
compile group: 'org.functionaljava', name: 'functionaljava-java8', version: '4.3'
168175
testCompile group: 'junit', name: 'junit', version: '4.+'
169176
testCompile group: 'com.pholser', name: 'junit-quickcheck-core', version: '0.5-alpha-1'
170177
testCompile group: 'com.pholser', name: 'junit-quickcheck-generators', version: '0.5-alpha-1'

fpinjava-parent/fpinjava-common/src/main/java/com/fpinjava/common/Either.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package com.fpinjava.common;
22

3-
import com.fpinjava.common.Function;
4-
import com.fpinjava.common.List;
5-
import com.fpinjava.common.Supplier;
63

74
public abstract class Either<E, A> {
85

fpinjava-parent/fpinjava-common/src/main/java/com/fpinjava/common/List.java

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
import java.util.Collection;
44
import java.util.Set;
55
import java.util.TreeSet;
6+
import java.util.function.Consumer;
67

78
import static com.fpinjava.common.TailCall.ret;
89
import static com.fpinjava.common.TailCall.sus;
910

11+
1012
public abstract class List<A> {
1113

1214
public abstract A head();
@@ -62,6 +64,28 @@ private TailCall<Tuple<List<A>, List<A>>> splitAt_(List<A> acc, List<A> list, in
6264
: sus(() -> splitAt_(acc.cons(list.head()), list.tail(), i - 1));
6365
}
6466

67+
public void forEach(Consumer<A> effect) {
68+
List<A> workList = this;
69+
while (!workList.isEmpty()) {
70+
effect.accept(workList.head());
71+
workList = workList.tail();
72+
}
73+
}
74+
75+
public Option<A> getAt(int index) {
76+
return getAt(this, index).eval();
77+
}
78+
79+
public TailCall<Option<A>> getAt(List<A> list, int index) {
80+
return index >= list.length()
81+
? TailCall.ret(Option.none())
82+
: list.isEmpty()
83+
? TailCall.ret(Option.none())
84+
: index <= 0
85+
? TailCall.ret(Option.some(list.head()))
86+
: TailCall.sus(() -> getAt(list.tail(), index - 1));
87+
}
88+
6589
private List() {
6690
}
6791

@@ -251,10 +275,19 @@ private <B> TailCall<B> foldLeft_(B acc, List<A> list, B identity, Function<B, F
251275
identity, f));
252276
}
253277

278+
// private static <U, T> U foldLeftIterative(List<T> list, U seed, Function<U, Function<T, U>> f) {
279+
// List<T> workList = list;
280+
// U result = seed;
281+
// while (!workList.isEmpty()) {
282+
// result = f.apply(result).apply(workList.head());
283+
// workList = workList.tail();
284+
// }
285+
// return result;
286+
// }
287+
254288
@Override
255289
public <B> B foldRight(B identity, Function<A, Function<B, B>> f) {
256-
return foldLeft(Function.<B> identity(),
257-
g -> a -> b -> g.apply(f.apply(a).apply(b))).apply(identity);
290+
return this.reverse().foldLeft(identity, x -> y -> f.apply(y).apply(x));
258291
}
259292

260293
@Override
@@ -388,7 +421,7 @@ public static <T> List<T> reverse(List<T> list) {
388421
}
389422

390423
public static List<Integer> range(int start, int end) {
391-
return range_(list(), start, end - 1).eval();
424+
return range_(List.<Integer>list(), start, end - 1).eval();
392425
}
393426

394427
public static TailCall<List<Integer>> range_(List<Integer> acc, int start, int end) {
@@ -397,6 +430,16 @@ public static TailCall<List<Integer>> range_(List<Integer> acc, int start, int e
397430
: sus(() -> range_(new Cons<>(end, acc), start, end - 1));
398431
}
399432

433+
public static List<Long> range(long start, long end) {
434+
return range_(List.<Long>list(), start, end - 1).eval();
435+
}
436+
437+
public static TailCall<List<Long>> range_(List<Long> acc, long start, long end) {
438+
return start >= end + 1
439+
? ret(acc)
440+
: sus(() -> range_(new Cons<>(end, acc), start, end - 1));
441+
}
442+
400443
public static <A> List<A> fill(int n, Supplier<A> s) {
401444
return range(0, n).map(ignore -> s.get());
402445
}

fpinjava-parent/fpinjava-datastructures-solutions/src/main/java/com/fpinjava/datastructures/exercise05_15/Folds.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@ public static <A, B> B foldRightViaFoldLeft(List<A> list, B identity, Function<A
99
return list.reverse().foldLeft(identity, x -> y -> f.apply(y).apply(x));
1010
}
1111

12+
/*
13+
* Beware that this method is not stack safe.
14+
*/
1215
public static <A, B> B foldLeftViaFoldRight(List<A> list, B identity, Function<B, Function<A, B>> f) {
1316
return List.foldRight(list.reverse(), identity, x -> y -> f.apply(y).apply(x));
1417
}
15-
18+
19+
/*
20+
* Beware that this method is not stack safe.
21+
*/
1622
public static <A, B> B foldRightViaFoldLeft2(List<A> list, B identity, Function<A, Function<B, B>> f) {
1723
return list.foldLeft(Function.<B>identity(), g -> a -> b -> g.apply(f.apply(a).apply(b))).apply(identity);
1824
}
1925

26+
/*
27+
* Beware that this method is not stack safe.
28+
*/
2029
public static <A, B> B foldLeftViaFoldRight2(List<A> list, B identity, Function<B, Function<A, B>> f) {
2130
return List.foldRight(list, Function.<B>identity(), a -> g -> b -> g.apply(f.apply(b).apply(a))).apply(identity);
2231
}

fpinjava-parent/fpinjava-functionalparallelism-solutions/src/main/java/com/fpinjava/functionaparallelism/exercise03/Par.java renamed to fpinjava-parent/fpinjava-functionalparallelism-solutions/src/main/java/com/fpinjava/functionalparallelism/exercise03/Par.java

Lines changed: 11 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,33 @@
1-
package com.fpinjava.functionaparallelism.exercise03;
1+
package com.fpinjava.functionalparallelism.exercise03;
22

3-
import java.util.concurrent.Callable;
43
import java.util.concurrent.ExecutionException;
54
import java.util.concurrent.ExecutorService;
6-
import java.util.concurrent.Executors;
75
import java.util.concurrent.Future;
86
import java.util.concurrent.TimeUnit;
97
import java.util.concurrent.TimeoutException;
108

119
import com.fpinjava.common.Function;
12-
import com.fpinjava.common.List;
1310
import com.fpinjava.common.Option;
1411
import com.fpinjava.common.Supplier;
15-
import com.fpinjava.common.Tuple;
1612

17-
/*
18-
* What if `run` were backed by a `java.util.concurrent.ExecutorService`? You
19-
* may want to spend some time looking through the `java.util.concurrent`
20-
* package to see what other useful things you can find.
21-
*/
2213
public interface Par<A> extends Function<ExecutorService, Future<A>> {
2314

24-
public static Par<Integer> sum(List<Integer> ints) {
25-
if (ints.length() <= 1) {
26-
return Par.unit(() -> ints.headOption().getOrElse(0));
27-
} else {
28-
final Tuple<List<Integer>, List<Integer>> tuple = ints.splitAt(ints.length() / 2);
29-
return Par.map2(fork(() -> sum(tuple._1)), fork(() -> sum(tuple._2)), x -> y -> x + y);
30-
}
31-
}
32-
33-
/*-
34-
* `map2` doesn't evaluate the call to `f` in a separate logical thread, in
35-
* accord with our design choice of having `fork` be the sole function in the
36-
* API for controlling parallelism. We can always do `fork(map2(a,b)(f))` if
37-
* we want the evaluation of `f` to occur in a separate thread.
38-
*
39-
* This implementation of `map2` does _not_ respect timeouts. It simply passes
40-
* the `ExecutorService` on to both `Par` values, waits for the results of the
41-
* Futures `af` and `bf`, applies `f` to them, and wraps them in a
42-
* `UnitFuture`. In order to respect timeouts, we'd need a new `Future`
43-
* implementation that records the amount of time spent evaluating `af`, then
44-
* subtracts that time from the available time allocated for evaluating `bf`.
45-
*/
4615
public static <A, B, C> Par<C> map2(Par<A> a, Par<B> b, Function<A, Function<B, C>> f) {
4716
return (ExecutorService es) -> {
4817
Future<A> af = a.apply(es);
4918
Future<B> bf = b.apply(es);
5019
return new Map2Future<>(af, bf, f);
5120
};
5221
}
53-
22+
5423
public static class Map2Future<A, B, C> implements Future<C> {
55-
24+
5625
private volatile Option<C> cache = Option.none();
5726

5827
private final Future<A> a;
5928
private final Future<B> b;
6029
private final Function<A, Function<B, C>> f;
61-
30+
6231
public Map2Future(Future<A> a, Future<B> b, Function<A, Function<B, C>> f) {
6332
super();
6433
this.a = a;
@@ -91,13 +60,15 @@ public C get() throws InterruptedException, ExecutionException {
9160
}
9261

9362
@Override
94-
public C get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
63+
public C get(long timeout, TimeUnit unit) throws InterruptedException,
64+
ExecutionException, TimeoutException {
9565
return compute(TimeUnit.MILLISECONDS.convert(timeout, unit));
9666
}
97-
98-
private C compute(long timeoutMs) throws InterruptedException, ExecutionException, TimeoutException {
67+
68+
private C compute(long timeoutMs) throws InterruptedException,
69+
ExecutionException, TimeoutException {
9970
if (cache.isSome()) {
100-
return cache.get();
71+
return cache.get();
10172
} else {
10273
final long start = System.currentTimeMillis();
10374
final A ar = a.get(timeoutMs, TimeUnit.MILLISECONDS);
@@ -132,13 +103,7 @@ public static <A> Par<A> unit(Supplier<A> a) {
132103
* later in the chapter.
133104
*/
134105
public static <A> Par<A> fork(Supplier<Par<A>> a) {
135-
return es -> es.submit(new Callable<A>() {
136-
137-
@Override
138-
public A call() throws Exception {
139-
return a.get().apply(es).get();
140-
}
141-
});
106+
return es -> es.submit(() -> a.get().apply(es).get());
142107
}
143108

144109
public static <A> Par<A> lazyUnit(Supplier<A> a) {

0 commit comments

Comments
 (0)