【问题标题】:How can I define mutually recursive lambda functions in Java?如何在 Java 中定义相互递归的 lambda 函数?
【发布时间】:2021-12-11 22:55:39
【问题描述】:

我正在尝试将L-system 实现为函数。例如,dragon curve 看起来像这样:

static String F(int n) {
    return n == 0 ? "F" : F(n - 1) + "+" + G(n -1);
}

static String G(int n) {
    return n == 0 ? "G" : F(n - 1) + "-" + G(n -1);
}

@Test
void testDragonCurveAsStaticFunction() {
    assertEquals("F", F(0));
    assertEquals("F+G", F(1));
    assertEquals("F+G+F-G", F(2));
    assertEquals("F+G+F-G+F+G-F-G", F(3));
}

我想用 lambda 函数来实现它。参考recursion - Implement recursive lambda function using Java 8 - Stack Overflow得到了如下实现。

@Test
void testDragonCurveAsLambdaFunction() {
    interface IntStr { String apply(int i); }
    IntStr[] f = new IntStr[2];
    f[0] = n -> n == 0 ? "F" : f[0].apply(n - 1) + "+" + f[1].apply(n - 1);
    f[1] = n -> n == 0 ? "G" : f[0].apply(n - 1) + "-" + f[1].apply(n - 1);
    assertEquals("F", f[0].apply(0));
    assertEquals("F+G", f[0].apply(1));
    assertEquals("F+G+F-G", f[0].apply(2));
    assertEquals("F+G+F-G+F+G-F-G", f[0].apply(3));
}

有没有办法在不使用数组的情况下实现这一点?

但是我想创建一个通用的L-System,所以我不想为龙曲线定义一个新的类、接口或方法。

【问题讨论】:

    标签: java recursion lambda


    【解决方案1】:

    我尝试使用一个结合了通过构造函数或设置器设置的两个 IntStr 字段的类来实现它:

    interface IntStr { 
        String apply(Integer i); 
    }
        
    class Recursive {
        IntStr other;
        IntStr curr;
    
        public Recursive() {}
        
        public Recursive(String p1, String s1, String p2, String s2) {
            this.curr  = n -> n == 0 ? p1 : curr.apply(n - 1) + s1 + other.apply(n - 1);
            this.other = n -> n == 0 ? p2 : curr.apply(n - 1) + s2 + other.apply(n - 1);
        }
        
        public void setCurr(String p, String s) {
            this.curr  = n -> n == 0 ? p : curr.apply(n - 1) + s + other.apply(n - 1);
        }
       
        public void setOther(String p, String s) {
            this.other = n -> n == 0 ? p : curr.apply(n - 1) + s + other.apply(n - 1);
        }
    }
    

    那么下面的代码就成功了:

    void testDragonCurveAsLambdaFunction() {
        Recursive f1 = new Recursive("F", "+", "G", "-");
    // or using setters
    //  f1.setCurr("F", "+"); 
    //  f1.setOther("G", "-");
        assertEquals("F", f1.curr.apply(0));
        assertEquals("F+G", f1.curr.apply(1));
        assertEquals("F+G+F-G", f1.curr.apply(2));
        assertEquals("F+G+F-G+F+G-F-G", f1.curr.apply(3));
    }
    

    使用AtomicReference 作为IntStr 引用的容器而不创建Recursive 类的示例:

    void testDragonCurveAsLambdaFunction() {
        AtomicReference<IntStr> 
            curr  = new AtomicReference<>(), 
            other = new AtomicReference<>(); 
        
        curr.set(n -> n == 0 ? "F" : curr.get().apply(n - 1) + "+" + other.get().apply(n - 1));
        other.set(n -> n == 0 ? "G" : curr.get().apply(n - 1) + "-" + other.get().apply(n - 1));
    
        assertEquals("F", curr.get().apply(0));
        assertEquals("F+G", curr.get().apply(1));
        assertEquals("F+G+F-G", curr.get().apply(2));
        assertEquals("F+G+F-G+F+G-F-G", curr.get().apply(3));
    }
    

    【讨论】:

    • 我想创建一个通用的 L-System,所以我不想为龙曲线定义一个新类。
    • 好吧,局部变量必须是有效的 final 才能在 lambdas 中使用,所以无论如何你必须使用容器作为 IntStr 引用,例如数组、另一个类或 @987654329 @.
    【解决方案2】:

    我找到了一个使用 Map 的解决方案。

    @FunctionalInterface
    interface IntStr {
    
        String apply(int n);
    
        static IntStr cond(String then, IntStr... otherwise) {
            return n -> n == 0 ? then
                : Stream.of(otherwise)
                    .map(f -> f.apply(n - 1))
                    .collect(Collectors.joining());
        }
    
        static IntStr constant(String string) {
            return n -> string;
        }
    
        static IntStr call(Map<String, IntStr> map, String functionName) {
            return n -> map.get(functionName).apply(n);
        }
    }
    

    @Test
    void testDragonCurveAsLambda() {
        Map<String, IntStr> map = new HashMap<>();
        map.put("F", IntStr.cond("F",
            IntStr.call(map, "F"),
            IntStr.constant("+"),
            IntStr.call(map, "G")));
        map.put("G", IntStr.cond("G",
            IntStr.call(map, "F"),
            IntStr.constant("-"),
            IntStr.call(map, "G")));
        IntStr f = map.get("F");
        assertEquals("F", f.apply(0));
        assertEquals("F+G", f.apply(1));
        assertEquals("F+G+F-G", f.apply(2));
        assertEquals("F+G+F-G+F+G-F-G", f.apply(3));
    }
    

    【讨论】:

    • 这是在接口中使用静态方法的一个很好的例子,但通常你已经用地图替换了数组:)
    猜你喜欢
    • 2020-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 1970-01-01
    相关资源
    最近更新 更多