The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

Susan Harkins (424) [Avatar] Offline
#1
Please post errors in the published version of Functional Programming in Java here. If necessary, we'll publish a comprehensive list for everyone's convenience. Thank you!

Susan Harkins
Errata Editor
Manning Publications
Pierre-Yves Saumont (182) [Avatar] Offline
#2
Hi Susan,

Is there a way for the author to remove spam messages, success as https://forums.manning.com/posts/list/39375.page?

Pierre-Yves
gmariotti (3) [Avatar] Offline
#3
Hey, these are the errors I think I have found in the printed copy:

(40)
Function<Double, Double> sin = this.sin(x);
should be
Function<Double, Double> sin = this::sin;


(47)
<A, B, C, D> Function<A, Function<B, Function<C, Function<D, E>>>> f() {
should be
<A, B, C, D> Function<A, Function<B, Function<C, Function<D, String>>>> f() {


(55) figure 2.4
Try<Tuple<Boolean, T>>>
should be
Result<Tuple<Boolean, T>>>


(70)
import static emailvalidation4
should be
import static com.fpinjava.makingjavafunctional.exercise03_01


(81) Exercise 3.10
Not section 3.10 but section 3.1.1

(116)
private static <T> TailCall<List<BigInteger>> fibo_(..)
should be
private static TailCall<List<BigInteger>> fibo_(..)
Pierre-Yves Saumont (182) [Avatar] Offline
#4
Hi,

Thanks a lot for pointing these errors! We'll fix them in next print.

Pierre-Yves
447383 (5) [Avatar] Offline
#5
Printed version and epub-version:
Page 134: Solution 5.3
The cons method is ....
should be
The toString method is ....
447383 (5) [Avatar] Offline
#6
Fig. 5.6
The list2 arrow should point to the element l instead of i.
Susan Harkins (424) [Avatar] Offline
#7
The current errata list for Functional Programming in Java is available at https://manning-content.s3.amazonaws.com/download/9/8a466fb-75d9-4f9d-9330-ff802907e195/Saumont_FPinJava_Err2.html.

Thank you,
Susan Harkins
Errata Editor
Manning Publications
Qinghua Gao (2) [Avatar] Offline
#8
Hi, I suspect the following are errors:

(page 12, first paragraph)
This combine method is somewhat equivalent to the following

might be
This fill method is somewhat equivalent to the following


(page 24, last paragraph)
you could test the second parameter and return a value if it's null

might be
you could test the second parameter and return a value if it's 0


(page 55, middle)
x ? x.first
y ? y._1
x ? x._2

might be
x -> x.first
y -> y._1
x -> x._2


(page 68, last paragraph)
because it has only three lines of code:

might be
because it has only four lines of code:


(page 152, code)
int localPort throws IOException

might be
int localPort) throws IOException


(page 240)
SOLUTION 9.2

might be
SOLUTION 9.1


(page 306, last paragraph)
If it is, it calls the remove method on the delegate

might be
If it is, it calls the delete method on the delegate


(page 430?, the 4th paragraph from the buttom)
change the domain, making it a function of (integer, non-null integer)?

might be
change the domain, making it a function of (integer, non-zero integer)
Qinghua Gao (2) [Avatar] Offline
#9
And:
(page 395, code)
assert x == 0;

might be
assert x != 0;


(page 396, code)
if (x != 0) throw new IllegalArgumentException("div. By 0");

might be
if (x == 0) throw new IllegalArgumentException("div. By 0");
Pierre-Yves Saumont (182) [Avatar] Offline
#10
447383 wrote:Printed version and epub-version:
Page 134: Solution 5.3
The cons method is ....
should be
The toString method is ....


The intended text was:

The Cons implementation is...

Thanks for spotting this.
Pierre-Yves Saumont (182) [Avatar] Offline
#11
Qinghua Gao wrote:Hi, I suspect the following are errors:

...


Thank you very much for spotting these errors! They will be added to the errata and fixed in the next print.
447791 (1) [Avatar] Offline
#12
The listing 2.2 on page 52 appears to have a few issues with it.

1. The definition of "compose" appears to be that the current/this/first function is to be applied to the second function. And the corollary: "andThen" appears to be defined such that the second function is to be applied to the current/this/first function.
The following methods adhere to this understanding:
- compose(f)
- andThen(f)
- compose(f,g)
- andThen(f,g)
- higherCompose()
- higherAndThen()

The following methods are reversed from this understanding:
- compose()
- andThen()

2. If the body of compose() and andThen() are expanded (that is, change y.compose(x) into y.apply(x.apply(z))), it seems that there really isn't a difference between the compose()/andThen() set and the higherCompose()/higherAndThen() set [other than issue #1 above]. Both sets return the same values. Am I missing something?
javabean68 (5) [Avatar] Offline
#13
Hi,

nice book! smilie

Thank you
Fabio
Pierre-Yves Saumont (182) [Avatar] Offline
#14
Hi Fabio,

I guess you figured the answer by yourself! ??
Pierre-Yves Saumont (182) [Avatar] Offline
#15
447791 wrote:The listing 2.2 on page 52 appears to have a few issues with it.

1. The definition of "compose" appears to be that the current/this/first function is to be applied to the second function. And the corollary: "andThen" appears to be defined such that the second function is to be applied to the current/this/first function.
The following methods adhere to this understanding:
- compose(f)
- andThen(f)
- compose(f,g)
- andThen(f,g)
- higherCompose()
- higherAndThen()

The following methods are reversed from this understanding:
- compose()
- andThen()

2. If the body of compose() and andThen() are expanded (that is, change y.compose(x) into y.apply(x.apply(z))), it seems that there really isn't a difference between the compose()/andThen() set and the higherCompose()/higherAndThen() set [other than issue #1 above]. Both sets return the same values. Am I missing something?


First of all, I am very sorry for not having answered in time. In fact I never received the notification, and I just saw your message more than four months later!

You are right about compose() and andThen() having their argument inverted compared to the corresponding methods or the higherCompose and higherAndThen functions. This is only a question of convention. The convention is that the composition of f and g is g(f(x)), so compose() and andThen() are indeed correct, and the others are wrong. Using defferent types would show this:

public static void main(String... args) {
  Function<Integer, Double> f = x -> x * 3.0;
  Function<Double, Long> g = x -> (long) (x + 3.0);
  //System.out.println(f.compose(g).apply(6)); // does not compile
  System.out.println(g.compose(f).apply(6));
  System.out.println(Function.<Integer, Double, Long>compose().apply(f).apply(g).apply(6));
  //System.out.println(Function.<Double, ???, ???>compose().apply(g).apply(f).apply(6)); // does not compile
  System.out.println(Function.<Integer, Double, Long>higherCompose().apply(g).apply(f).apply(6));
  System.out.println(Function.<Integer, Double, Long>higherAndThen().apply(f).apply(g).apply(6));
  System.out.println(g.apply(f.apply(6)));
}


Regarding the second point, you're not missing anything. higherCompose and higherAndThen are just a mean to define composition while not using the compose and andThen methods defined in the interface. They are in fact the only higher order functions that are necessary.
javabean68 (5) [Avatar] Offline
#16
Pierre-Yves Saumont wrote:Hi Fabio,

I guess you figured the answer by yourself! ??


Yep! Sorry. smilie Thank you for your book!
javabean68 (5) [Avatar] Offline
#17
An alternative solution to exercise 03.08
Hi Pierre-Yves,

I am reading your book and I really appreciate the way it alternates explanations with exercises!

I have tried to solve the exercise 03.08 and I found the following working solution just applying what you said on the textbook:


  public static <T, U, V> Function<U, Function<T, V>> reverseArgs(Function<T, Function<U, V>> f) {
    //in: curried function
    return (U u) -> (T t)  -> f.apply(t).apply(u);
  }

  public static <T, U> U foldRight(List<T> ts, U identity,
                                   Function<T, Function<U, U>> f) {
    Function<U, Function<T, U>> g = reverseArgs(f);
    final List<T> copied = copy(ts);
    
    Collections.reverse(copied);
    U result = identity;
    for (T t : copied) {
      //result = f.apply(t).apply(result); //corecursive
      
      result = g.apply(result).apply(t); //recursive
    }
    return result;
  }


Setting the things so helps me to express the corecursive vs the recursive form in a more expressive way to me.


recursive: g.apply(result) is for me f(n) which I apply to n-1



corecursive: g.apply(t) is for me f(n-1) which I apply to n


I also inverted the arguments of the function...The tests are green but I wonder whether this approach is right.

Thank you very much!

Regards
Fabio
Pierre-Yves Saumont (182) [Avatar] Offline
#18
Hi Fabio,

Both of your implementations may be considered ok since they give the correct result. However, none is the solution of exercise 3.8 since they are not recursive, but iterative. A recursive function is a function calling itself as part of a further computation. A corecursive function is a function calling itself as the last operation it does (hence not as part of a further computation). The solution of exercise 3.8 is:

  public static <T, U> U foldRight(List<T> ts, U identity,  Function<T, Function<U, U>> f) {
    return ts.isEmpty()
        ? identity
        : f.apply(head(ts)).apply(foldRight(tail(ts), identity, f));
  }


Here, you see that the function calls itself and then calls the result of applying f to head(ts), which is a function, to the result of the recursive call.

A corecursive function example could be:

  public static <T, U> U foldLeft(List<T> ts, U identity, Function<U, Function<T, U>> f) {
    return ts.isEmpty()
            ? identity
            : foldLeft(tail(ts), f.apply(identity).apply(head(ts)), f);
  }


Here, the "recursive" call to foldLeft is the last thing the method does. The result is not part of a further computation. So it is a corecursive function (also called "tail recursive", which is not very well chosen.)

foldright may be implemented through iteration (as you did), or through corecursion (applying foldLeft after having reversed the list), but this is not equivalent to a recursive implementation. These are different implementations giving the same result (at least for short lists!).

280126 (3) [Avatar] Offline
#19
Hi, I apologize for wrong posts I've submitted before I've finished.
I kindly ask admin to remove this and post below.
280126 (3) [Avatar] Offline
#20
[]