使用Java8实现递归lambda函数

使用Java8实现递归lambda函数,java,recursion,lambda,java-8,Java,Recursion,Lambda,Java 8,Java 8引入了lambda函数,我想实现类似阶乘的功能: IntToDoubleFunction fact = x -> x == 0 ? 1 : x * fact.applyAsDouble(x-1); 汇编返回 error: variable fact might not have been initialized 如何引用函数本身。类是匿名的,但实例存在:它被称为fact一种解决方案是将此函数定义为实例属性 import java.util.function.*; pu

Java 8引入了lambda函数,我想实现类似阶乘的功能:

 IntToDoubleFunction fact = x -> x == 0 ? 1 : x * fact.applyAsDouble(x-1);
汇编返回

  error: variable fact might not have been initialized

如何引用函数本身。类是匿名的,但实例存在:它被称为
fact

一种解决方案是将此函数定义为实例属性

import java.util.function.*;
public class Test{

    IntToDoubleFunction fact = x -> { return  ( x == 0)?1:x* fact.applyAsDouble(x-1);};

    public static void main(String[] args) {
      Test test = new Test();
      test.doIt();
    }

    public void doIt(){
       System.out.println("fact(3)=" + fact.applyAsDouble(3));
    }
}

另一个版本使用累加器,这样可以优化递归。 移动到通用接口定义

Function<Integer,Double> facts = x -> { return  ( x == 0)?1:x* facts.apply(x-1);};
BiFunction<Integer,Double,Double> factAcc= (x,acc) -> { return (x == 0)?acc:factAcc.apply(x- 1,acc*x);};
Function<Integer,Double> fact = x -> factAcc.apply(x,1.0) ;

public static void main(String[] args) {
   Test test = new Test();
   test.doIt();
}

 public void doIt(){
int val=70;
System.out.println("fact(" + val + ")=" + fact.apply(val));
}
}
Function facts=x->{return(x==0)?1:x*facts.apply(x-1);};
双函数factAcc=(x,acc)->{return(x==0)?acc:factAcc.apply(x-1,acc*x);};
函数事实=x->factAcc.apply(x,1.0);
公共静态void main(字符串[]args){
测试=新测试();
test.doIt();
}
公共无效doIt(){
int-val=70;
System.out.println(“事实(“+val+””)=“+fact.apply(val));
}
}

本地和匿名类以及lambda,在创建本地变量时通过值捕获它们。因此,它们不可能通过捕获局部变量来引用自己,因为在创建它们时,指向自身的值还不存在

本地类和匿名类中的代码仍然可以使用this引用它们自己。但是,
在lambda中并不指lambda;它指的是来自外部范围的

您可以捕获可变的数据结构,如数组:

IntToDoubleFunction[] foo = { null };
foo[0] = x -> { return  ( x == 0)?1:x* foo[0].applyAsDouble(x-1);};

虽然这不是一个优雅的解决方案。

您可以将递归lambda定义为实例或类变量:

static DoubleUnaryOperator factorial = x -> x == 0 ? 1
                                          : x * factorial.applyAsDouble(x - 1);
例如:

class Test {
    static DoubleUnaryOperator factorial = x -> x == 0 ? 1
                                             : x * factorial.applyAsDouble(x - 1));
    public static void main(String[] args) {
        System.out.println(factorial.applyAsDouble(5));
    }
}
打印
120.0

公共类主目录{
public class Main {
    static class Wrapper {
        Function<Integer, Integer> f;
    }

    public static void main(String[] args) {
        final Wrapper w = new Wrapper();
        w.f = x -> x == 0 ? 1 : x * w.f.apply(x - 1);
        System.out.println(w.f.apply(10));
    }
}
静态类包装器{ 函数f; } 公共静态void main(字符串[]args){ 最终包装w=新包装(); w、 f=x->x==0?1:x*w.f.apply(x-1); 系统输出打印LN(w.f.apply(10)); } }
一种方法是编写一个辅助函数,
helper
,它接受一个函数和一个数字作为参数,然后编写实际需要的函数,
fact=helper(helper,x)

像这样:

BiFunction<BiFunction, Double, Double> factHelper =
        (f, x) -> (x == 0) ? 1.0 : x*(double)f.apply(f,x-1);
Function<Double, Double> fact =
        x -> factHelper.apply(factHelper, x);

由于
factHelper
不太完美的泛型类型而产生的代码气味现在包含在lambda中(或者,我敢说,封装在lambda中),确保
factHelper
永远不会在不知不觉中被调用。

我手边没有Java8编译器,因此无法测试我的答案。但是,如果您将“事实”变量定义为最终变量,它会起作用吗

final IntToDoubleFunction fact = x -> {
    return  ( x == 0)?1:x* fact.applyAsDouble(x-1);
};
final IntToDoubleFunction事实=x->{
返回值(x==0)?1:x*fact.applyAsDouble(x-1);

};以下方法可行,但看起来确实很神秘

import java.util.function.Function;

class recursion{

Function<Integer,Integer>  factorial_lambda;  // The positions of the lambda declaration and initialization must be as is.

public static void main(String[] args) {  new recursion();}

public recursion() {
 factorial_lambda=(i)->{
        if(i==1)
            return 1;
        else
            return i*(factorial_lambda.apply(i-1));
    };
    System.out.println(factorial_lambda.apply(5));
 }
}

// Output 120
import java.util.function.function;
类递归{
函数factorial_lambda;//lambda声明和初始化的位置必须保持原样。
公共静态void main(字符串[]args){new recursion();}
公共递归(){
阶乘λ=(i)->{
如果(i==1)
返回1;
其他的
返回i*(阶乘λ应用(i-1));
};
System.out.println(阶乘λ应用(5));
}
}
//输出120

我在今年的JAX上听说“lambads不支持递归”。这句话的意思是,lambda中的“this”总是指周围的类

但我设法定义了递归lambda,至少我是如何理解术语“递归”的,它是这样的:

interface FacInterface {
  int fac(int i);
}
public class Recursion {
  static FacInterface f;
  public static void main(String[] args)
  {
    int j = (args.length == 1) ? new Integer(args[0]) : 10;
    f = (i) -> { if ( i == 1) return 1;
      else return i*f.fac( i-1 ); };
    System.out.println( j+ "! = " + f.fac(j));
  }
}
将其保存在一个文件“Recursion.java”中,并使用两个命令“javac Recursion.java”和“javarecursion”对我有效


clou将lambda必须实现的接口作为字段变量保留在周围的类中。lambda可以引用该字段,而该字段将不会隐式为最终字段。

有点像第一次回复

public static Function<Integer,Double> factorial;

static {
    factorial = n -> {
        assert n >= 0;
        return (n == 0) ? 1.0 : n * factorial.apply(n - 1);
    };
}
公共静态函数阶乘;
静止的{
阶乘=n->{
断言n>=0;
收益率(n==0)?1.0:n*factorial.apply(n-1);
};
}

您还可以通过创建大小为1的最终数组(比如函数[])将其定义为局部变量,然后将函数分配给元素0。如果您需要确切的语法,请告诉我,我通常使用(一次用于定义的所有函数接口)通用帮助器类来包装函数接口类型的变量。 这种方法解决了局部变量初始化的问题,并使代码看起来更清晰

如果出现此问题,代码如下所示:

// Recursive.java
// @param <I> - Functional Interface Type
public class Recursive<I> {
    public I func;
}

// Test.java
public double factorial(int n) {

    Recursive<IntToDoubleFunction> recursive = new Recursive<>();
    recursive.func = x -> (x == 0) ? 1 : x * recursive.func.applyAsDouble(x - 1);

    return recursive.func.applyAsDouble(n);
}
//Recursive.java
//@param-功能接口类型
公共类递归{
公共职能;
}
//Test.java
公共双阶乘(整数n){
递归=新的递归();
recursive.func=x->(x==0)?1:x*recursive.func.applyasdoull(x-1);
返回recursive.func.applyasdoull(n);
}

问题在于,lambda函数想要对
最终的
变量进行操作,而我们需要一个可变的
函数
-引用,可以用lambda替换

最简单的技巧似乎是将变量定义为成员变量,编译器不会抱怨

我将我的示例更改为使用
IntUnaryOperator
而不是
IntToDoubleFunction
,因为这里我们只是对
整数进行操作

import org.junit.Test;
import java.util.function.IntUnaryOperator;
import static org.junit.Assert.assertEquals;

public class RecursiveTest {
    private IntUnaryOperator operator;

    @Test
    public void factorialOfFive(){
        IntUnaryOperator factorial = factorial();
        assertEquals(factorial.applyAsInt(5), 120); // passes
    }

    public IntUnaryOperator factorial() {
        return operator = x -> (x == 0) ? 1 : x * operator.applyAsInt(x - 1);
    }
}

这是一个不依赖副作用的解决方案。为了使目的更有趣,假设您希望在递归上进行抽象(否则实例字段解决方案是完全有效的)。 诀窍是使用匿名类获取“this”引用:

public static IntToLongFunction reduce(int zeroCase, LongBinaryOperator reduce) {
  return new Object() {
    IntToLongFunction f = x -> x == 0
                               ? zeroCase
                               : reduce.applyAsLong(x, this.f.applyAsLong(x - 1));
  }.f;
}

public static void main(String[] args) {
  IntToLongFunction fact = reduce(1, (a, b) -> a * b);
  IntToLongFunction sum = reduce(0, (a, b) -> a + b);
  System.out.println(fact.applyAsLong(5)); // 120
  System.out.println(sum.applyAsLong(5)); // 15
}
鉴于lambda中的“this”指的是包含类,因此以下编译没有错误(当然,添加了依赖项):

公共类MyClass{
函数sourceToStruct=源->{
自定义结构结果;
目标价值;
for(字符串键:source.keySet()){
value=source.get(键);
if(映射的值实例){
public static IntToLongFunction reduce(int zeroCase, LongBinaryOperator reduce) {
  return new Object() {
    IntToLongFunction f = x -> x == 0
                               ? zeroCase
                               : reduce.applyAsLong(x, this.f.applyAsLong(x - 1));
  }.f;
}

public static void main(String[] args) {
  IntToLongFunction fact = reduce(1, (a, b) -> a * b);
  IntToLongFunction sum = reduce(0, (a, b) -> a + b);
  System.out.println(fact.applyAsLong(5)); // 120
  System.out.println(sum.applyAsLong(5)); // 15
}
public class MyClass {
    Function<Map, CustomStruct> sourceToStruct = source -> {
        CustomStruct result;
        Object value;

        for (String key : source.keySet()) {
            value = source.get(key);

            if (value instanceof Map) {
                value = this.sourceToStruct.apply((Map) value);
            }

            result.setValue(key, value);
        }

        return result;
    };
}
public static interface Recursable<T, U> {
    U apply(T t, Recursable<T, U> r);
}

public static <T, U> Function<T, U> recurse(Recursable<T, U> f) {
    return t -> f.apply(t, f);
}
Function<Integer, Double> fact = recurse(
    (i, f) -> 0 == i ? 1 : i * f.apply(i - 1, f));
public class LambdaExperiments {

  @FunctionalInterface
  public interface RFunction<T, R> extends Function<T, R> {
    R recursiveCall(Function<? super T, ? extends R> func, T in);

    default R apply(T in) {
      return recursiveCall(this, in);
    }
  }

  @FunctionalInterface
  public interface RConsumer<T> extends Consumer<T> {
    void recursiveCall(Consumer<? super T> func, T in);

    default void accept(T in) {
      recursiveCall(this, in);
    }
  }

  @FunctionalInterface
  public interface RBiConsumer<T, U> extends BiConsumer<T, U> {
    void recursiveCall(BiConsumer<T, U> func, T t, U u);

    default void accept(T t, U u) {
      recursiveCall(this, t, u);
    }
  }

  public static void main(String[] args) {
    RFunction<Integer, Integer> fibo = (f, x) -> x > 1 ? f.apply(x - 1) + f.apply(x - 2) : x;

    RConsumer<Integer> decreasingPrint = (f, x) -> {
      System.out.println(x);
      if (x > 0) f.accept(x - 1);
    };

    System.out.println("Fibonnaci(15):" + fibo.apply(15));

    decreasingPrint.accept(5);
  }
}
public class Recursive<I> {
    private Recursive() {

    }
    private I i;
    public static <I> I of(Function<RecursiveSupplier<I>, I> f) {
        Recursive<I> rec = new Recursive<>();
        RecursiveSupplier<I> sup = new RecursiveSupplier<>();
        rec.i = f.apply(sup);
        sup.i = rec.i;
        return rec.i;
    }
    public static class RecursiveSupplier<I> {
        private I i;
        public I call() {
            return i;
        }
    }
}
Function<Integer, Integer> factorial = Recursive.of(recursive ->
        x -> x == 0 ? 1 : x * recursive.call().apply(x - 1));
System.out.println(factorial.apply(5));
public static int factorial(int i) {
    final UnaryOperator<Integer> func = x -> x == 0 ? 1 : x * factorial(x - 1);
    return func.apply(i);
}
import java.util.function.Function;

public class Fib {

   static Function<Integer, Integer> fib;

   public static void main(String[] args) {
       fib = (n) -> { return n > 1 ? fib.apply(n-1) + fib.apply(n-2) : n; };

       for(int i = 0; i < 10; i++){
           System.out.println("fib(" + i + ") = " + fib.apply(i));
       }
   }
}
public static interface Recursable<T, U> {
        U apply(T t, Recursable<T, U> r);

        public static <T, U> Function<T, U> recurseable(Recursable<T, U> f) {
            return t -> f.apply(t, f);
        }
}
IntToDoubleFunction fact = x -> x == 0 ? 1 : x * this.fact.applyAsDouble(x-1);
final IntToDoubleFunction fact = x -> x == 0 ? 1 : x * this.fact.applyAsDouble(x-1);
UnaryOperator<Long> fact = x -> x == 0 ? 1  : x * this.fact.apply(x - 1 );
static final UnaryOperator<Long> fact = x -> x== 0? 1: x * MyFactorial.fact.apply(x - 1 );
IntToDoubleFunction fact = new IntToDoubleFunction() {
    @Override
    public double applyAsDouble(int x) {
        return x == 0 ? 1 : x * this.applyAsDouble(x-1);
    }
};
interface MyOwnFunction<T,R>{
    R apply(MyOwnFunction<T,R> self,T arg);
}
public static <T, R> Function<T, R> fixedPointCombinator(Function<Function<T, R>, Function<T, R>> f) {
    return new Function<T, R>() {
        @Override
        public R apply(T n) {
            return f.apply(this).apply(n);
        }
    };
}
Function<Function<Integer, Double>, Function<Integer, Double>> fact =
    self -> n -> n == 0 ? 1 : n * self.apply(n - 1);

System.out.println(fixedPointCombinator(fact).apply(10));
3628800.0