2017-09-22 21 views
7

Gần đây tôi đã xem đoạn mã này trong Java. Nó liên quan đến chức năng và in số mã số và nó hoạt động.Phần này của cuộc gọi lambda đệ quy trong Java làm việc

public class AppLambdaSubstitution { 

public static Function<Integer, Integer> Y(Function<Function<Integer, Integer>, Function<Integer, Integer>> f) { 
    return x -> f.apply(Y(f)).apply(x); 
} 

public static void main(String[] args) { 
    Function<Integer, Integer> fib = Y(
      func -> x -> { 
     if (x < 2) 
      return x; 
     else 
      return func.apply(x - 1) + func.apply(x - 2); 
    }); 

    IntStream.range(1,11). 
    mapToObj(Integer::valueOf). 
    map(fib).forEach(System.out::println); 
    } 
} 

Phần tôi nhầm lẫn là return x -> f.apply(Y(f)).apply(x);. Không phải là Y(f) một cuộc gọi đệ quy đến phương thức Y? Chúng tôi tiếp tục gọi nó với hàm f làm tham số. Đối với tôi, không có trường hợp cơ bản nào cho cuộc gọi đệ quy này để trở về. Tại sao không có tràn kết quả từ một cuộc gọi đệ quy vô tận?

+3

Lệnh 'Y (f)' gọi là bên trong một lambda và lambda đó chỉ được thực thi nếu 'f' chọn gọi nó. – 4castle

+4

https://en.wikipedia.org/wiki/Fixed-point_combinator – pvg

Trả lời

5

Về cơ bản bạn đang thiếu điểm x -> f.apply(Y(f)).apply(x); sẽ không gọi apply, nó sẽ return a Function.

Đó chỉ là một cách rất phức tạp (và không trực quan?) Để hiển thị hàm currying và đệ quy IMO. Mọi thứ sẽ đơn giản hơn nhiều nếu bạn thay thế một vài thứ và làm cho nó dễ đọc hơn một chút.

xây dựng này:

Function<Function<Integer, Integer>, Function<Integer, Integer>> 

là không cần thiết ở tất cả, kể từ khi thông số bên trái là không sử dụng ở tất cả. Nó chỉ đơn giản là cần thiết để có được một tổ chức của một trong những quyền. Vì vậy, thông số left có thể là bất cứ điều gì ở tất cả (sau này tôi sẽ thay thế nó bằng Supplier - điều đó cũng không cần thiết, nhưng chỉ để chứng minh một điểm).

Trên thực tế tất cả các bạn quan tâm ở đây là Function này mà không tính toán thực tế cho mỗi phần tử của Stream:

public static Function<Integer, Integer> right() { 

    return new Function<Integer, Integer>() { 
     @Override 
     public Integer apply(Integer x) { 
      if (x < 2) { 
       return x; 
      } else { 
       return apply(x - 1) + apply(x - 2); 
      } 
     } 
    }; 
} 

Bây giờ bạn có thể viết rằng toàn bộ cấu trúc với:

Supplier<Function<Integer, Integer>> toUse =() -> right(); 
Function<Integer, Integer> fib = curry(toUse); 
IntStream.range(1, 11) 
      .mapToObj(Integer::valueOf) 
      .map(fib) 
      .forEach(System.out::println); 

này Supplier<Function<Integer, Integer>> toUse =() -> right(); nên làm cho bạn hiểu lý do tại sao trong ví dụ trước (Function<Function, Function>) cần phần bên trái - chỉ để giữ một số right một.

Nếu bạn nhìn gần hơn, bạn có thể nhận thấy rằng Supplierhoàn toàn không cần thiết, do đó bạn thậm chí hơn nữa có thể đơn giản hóa nó với:

IntStream.range(1, 11) 
     .mapToObj(Integer::valueOf) 
     .map(right()) 
     .forEach(System.out::println); 
Các vấn đề liên quan