Skip to content

Commit

Permalink
More exercises from Chapter 5.
Browse files Browse the repository at this point in the history
  • Loading branch information
sbordet committed Apr 15, 2014
1 parent bce1fa0 commit 709cdfc
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 3 deletions.
22 changes: 19 additions & 3 deletions src/main/java/fpinscala/chapter5/Exercise_5_02.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ public static <S> Flow<S> take(Flow<S> flow, int n)
// recursively call itself changing the value of n at each recursion,
// accumulating into a new Flow (it is evident that this is a fold right).
//
// The problem lies in the fact that take() takes a Flow, while the
// The problem lies in the fact that take() takes a Flow<T>, while the
// Flow constructor takes a Supplier<Flow<T>>.
// Differently from Scala, we have to create the Supplier<Flow<T>> on
// the fly to avoid the invocation of get() to "realize" the tail.
// In Java we have to create the Supplier<Flow<T>> explicitly
// to avoid the invocation of get() to "realize" the tail.
//
// As result, this method is not really recursive when called because
// it just builds the first element of the flow.
Expand All @@ -40,11 +40,27 @@ public static <S> Flow<S> take(Flow<S> flow, int n)
return new Flow<>(flow.head, () -> take(flow.tail.get(), n - 1));
}

public static <S> Flow<S> drop(Flow<S> flow, int n)
{
if (flow.isEmpty())
return flow;
if (n == 0)
return flow;
return drop(flow.tail.get(), n - 1);
}

public static void main(String[] args)
{
Flow<Integer> flow = Flow.of(1, 2, 3, 4);

System.out.println(take(Flow.empty(), 2).toCons());
System.out.println(take(flow, 0).toCons());
System.out.println(take(flow, 2).toCons());
System.out.println(take(flow, 5).toCons());
System.out.println();
System.out.println(drop(Flow.empty(), 2).toCons());
System.out.println(drop(flow, 0).toCons());
System.out.println(drop(flow, 2).toCons());
System.out.println(drop(flow, 5).toCons());
}
}
36 changes: 36 additions & 0 deletions src/main/java/fpinscala/chapter5/Exercise_5_03.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright (c) 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fpinscala.chapter5;

import java.util.function.Predicate;

public class Exercise_5_03
{
public static <S> Flow<S> takeWhile(Flow<S> flow, Predicate<S> p)
{
if (flow.isEmpty())
return flow;
if (!p.test(flow.head.get()))
return Flow.empty();
return new Flow<>(flow.head, () -> takeWhile(flow.tail.get(), p));
}

public static void main(String[] args)
{
Flow<Integer> flow = Flow.of(1, 2, 3, 4);
System.out.println(takeWhile(flow, i -> i < 3).toCons());
}
}
52 changes: 52 additions & 0 deletions src/main/java/fpinscala/chapter5/Exercise_5_04.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fpinscala.chapter5;

import java.util.function.Predicate;

public class Exercise_5_04
{
public static <S> boolean exists(Flow<S> flow, Predicate<S> p)
{
// The key point to understand is that the we need to "realize" the second argument of f(),
// either directly (by calling get()) or indirectly (for example by returning it form f(),
// since the foldRight() algorithm "realizes" the return value of f()), in order to proceed
// with the iteration. If the second argument is not "realized", the iteration stops.
//
// In exists(), the predicate will fail until the element is found, therefore each time the
// predicate fails, the iteration will continue.
return flow.foldRight(false, (element, lazyResult) -> p.test(element) ? () -> true : lazyResult);

// Another way of writing it, more similar to the Scala version.
// Note how in this version the "realization" of the second argument is explicit.
// return flow.foldRight(false, (element, lazyResult) -> () -> p.test(element) || lazyResult.get());
}

public static <S> boolean forAll(Flow<S> flow, Predicate<S> p)
{
// Like above, we need to "realize" the second argument to iterate.
// When the predicate fails, iteration is stopped.
return flow.foldRight(true, (element, lazyResult) -> p.test(element) ? lazyResult : () -> false);
}

public static void main(String[] args)
{
Flow<Integer> flow = Flow.of(1, 2, 3, 4);
System.out.println(exists(flow, i -> i == 3));
System.out.println(forAll(flow, i -> i < 2));
System.out.println(forAll(flow, i -> i < 5));
}
}
13 changes: 13 additions & 0 deletions src/main/java/fpinscala/chapter5/Flow.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package fpinscala.chapter5;

import java.util.function.BiFunction;
import java.util.function.Supplier;

import fpinscala.chapter3.Cons;
Expand Down Expand Up @@ -64,6 +65,18 @@ public boolean isEmpty()
return this == EMPTY;
}

public <S> S foldRight(S value, BiFunction<T, Supplier<S>, Supplier<S>> f)
{
if (isEmpty())
return value;
// The result of f.apply() is always "realized" by calling get().
// In order to proceed with the iteration, the user-supplied function f
// must either explicitly call get() on the second argument (which "realizes"
// the tail) or the return value of f must depend on the second argument so
// that "realizing" the return value will also "realize" the second argument.
return f.apply(head.get(), () -> tail.get().foldRight(value, f)).get();
}

public Cons<T> toCons()
{
return Exercise_5_01.toCons(this);
Expand Down

0 comments on commit 709cdfc

Please sign in to comment.