美文网首页KotlinKotlinJava 8 · Java 9 · Java X · Java 实践指北
使用 Kotlin 实现 Y 组合子(Y-Combinator)

使用 Kotlin 实现 Y 组合子(Y-Combinator)

作者: 光剑书架上的书 | 来源:发表于2017-07-28 00:00 被阅读104次

    使用 Kotlin 实现 Y 组合子(Y-Combinator)


    《Kotlin极简教程》正式上架:

    点击这里 > 去京东商城购买阅读

    点击这里 > 去天猫商城购买阅读

    非常感谢您亲爱的读者,大家请多支持!!!有任何问题,欢迎随时与我交流~


    我们可以使用 Kotlin FP (Lambda, function) 写一个 Y-combinator 函数吗?

    Y = λf.(λx.f (x x)) (λx.f (x x))
    

    我们知道,In JS:

    function Y(f) {
        return (function (g) {
            return g(g);
        })(function (g) {
            return f(function (x) {
                return g(g)(x);
            });
        });
    }
    
    var fact = Y(function (rec) {
        return function (n) {
            return n == 0 ? 1 : n * rec(n - 1);
        };
    });
    

    In Coffee:

    coffee> Y = (f) -> ((x) -> (x x)) ((x) -> (f ((y) -> ((x x) y))))
    [Function]
    
    coffee> fact = Y (f)  ->(n) -> if n==0 then 1 else n*f(n-1)
    [Function]
    
    coffee> fact(10)
    3628800
    

    在动态类型语言中,Y 组合子(Y-Combinator)实现起来很方便。

    使用 Java 的接口和类型转换我们也可以实现

    public class YCombinator {
    
        public static Lambda<Lambda> yCombinator2(final Lambda<Lambda> f) {
            return ((Lambda<Lambda>)(Object input) -> {
                final Lambda<Lambda> u = (Lambda<Lambda>)input;
                return u.call(u);
            }).call(
                ((Lambda<Lambda>)(Object input) -> {
                    final Lambda<Lambda> v = (Lambda<Lambda>)input;
                    return f.call((Lambda<Object>)(Object p) -> {
                        return v.call(v).call(p);
                    });
                })
            );
    
        }
    
        public static void main(String[] args) {
            Lambda<Lambda> y = yCombinator(
                (Lambda<Lambda>)(Object input) -> {
                    Lambda<Integer> fab = (Lambda<Integer>)input;
                    return (Lambda<Integer>)(Object p) -> {
                        Integer n = Integer.parseInt(p.toString());
                        if (n < 2) {
                            return Integer.valueOf(1);
                        } else {
                            return n * fab.call(n - 1);
                        }
                    };
                });
    
            System.out.println(y2.call(10));//输出: 3628800
        }
    
        interface Lambda<E> {
            E call(Object input);
        }
    
    }
    

    类似的使用 Kotlin 的 OOP 编程范式 Y 组合子 实现就是:

    object YCombinatorKt {
    
        fun yCombinator(f: Lambda<Lambda<*>>): Lambda<Lambda<*>> {
    
            return object : Lambda<Lambda<*>> {
    
                override fun call(n: Any): Lambda<*> {
                    val u = n as Lambda<Lambda<*>>
                    return u.call(u)
                }
            }.call(object : Lambda<Lambda<*>> {
    
                override fun call(n: Any): Lambda<*> {
                    val x = n as Lambda<Lambda<*>>
    
                    return f.call(object : Lambda<Any> {
                        override fun call(n: Any): Any {
                            return x.call(x).call(n)!!
                        }
                    })
                }
    
            }) as Lambda<Lambda<*>>
        }
    
        @JvmStatic fun main(args: Array<String>) {
    
            val y = yCombinator(object : Lambda<Lambda<*>> {
    
                override fun call(n: Any): Lambda<*> {
                    val fab = n as Lambda<Int>
    
                    return object : Lambda<Int> {
    
                        override fun call(n: Any): Int {
                            val n = Integer.parseInt(n.toString())
                            if (n < 2) {
                                return Integer.valueOf(1)
                            } else {
                                return n * fab.call(n - 1)
                            }
                        }
                    }
                }
            })
    
            println(y.call(10)) //输出: 3628800
        }
    
        interface Lambda<E> {
            fun call(n: Any): E
        }
    }
    

    当然,对于函数式编程也完全支持的 Kotlin 也有 FP 风格的Y 组合子实现:

    
    /**
     * Created by jack on 2017/7/9.
     *
     * lambda f. (lambda x. (f(x x)) lambda x. (f(x x)))
     *
     * FP YCombinator
     */
    
    // 为了方便易懂,使用 X 用做函数 (X)->Int 的别名
    typealias X = (Int) -> Int
    // G 递归引用 G 自己
    interface G : Function1<G, X>
    // create a fun G from lazy blocking
    fun G(block: (G) -> X) = object : G {
        // 调用函数自身 `block(g)` like as `g(g)`
        override fun invoke(g: G) = block(g)
    }
    
    typealias F = Function1<X, X>
    fun Y(f: F) = (fun(g: G) = g(g))(G { g -> f({ x -> g(g)(x) }) })
    
    val fact = Y {
        rec ->
        {
            n ->
            if (n == 0) 1 else n * rec(n - 1)
        }
    }
    val fib = Y { f ->
        {
            n ->
            if (n == 1 || n == 2) 1 else f(n - 1) + f(n - 2)
    
        }
    }
    
    
    fun main(args: Array<String>) {
        println(fact(10))
        println(fib(10))
    
        for (i in 1..10) {
            println("$i!= ${fact(i)}")
        }
    
        for (i in 1..10) {
            println("fib($i) = ${fib(i)}")
        }
    }
    
    
    

    其中,在接口 G 继承了Function1<G, X>接口:

    interface G : Function1<G, X>
    

    这个Function1 接口是继承自kotlin.Function 接口:

    public interface Function<out R>
    

    Function1 有一个抽象算子函数invoke , 用来调用入参 p1 :

    public interface Function1<in P1, out R> : kotlin.Function<R> {
        public abstract operator fun invoke(p1: P1): R
    }
    

    我们定义的 G 函数,入参是block函数 (G) -> X , block函数的入参又是 G 类型,通过 invoke 函数来实现 调用自身:

    fun G(block: (G) -> X) = object : G {
        // 调用函数自身 `block(g)` like as `g(g)`
        override fun invoke(g: G) = block(g)
    }
    

    这样,我们就可以实现一个 Y 组合子函数了:

    typealias F = Function1<X, X>
    
    fun Y(f: F) = (fun(g: G) = g(g))(G { g -> f({ x -> g(g)(x) }) })
    
    

    我们通过 Y 组合子定义阶乘递归函数和 Fibonacci 数列函数:

    val fact = Y {
        rec ->
        {
            n ->
            if (n == 0) 1 else n * rec(n - 1)
        }
    }
    val fib = Y { f ->
        {
            n ->
            if (n == 1 || n == 2) 1 else f(n - 1) + f(n - 2)
    
        }
    }
    

    测试代码:

    fun main(args: Array<String>) {
        val square: X = { x -> x * x }
        println(square(9))
    
        println(fact(10))
        println(fib(10))
    
        for (i in 1..10) {
            println("$i!= ${fact(i)}")
        }
    
        for (i in 1..10) {
            println("fib($i) = ${fib(i)}")
        }
    }
    
    

    Github 源码工程: https://github.com/EasyKotlin/chapter8_fp

    相关文章

      网友评论

      • 3Zero:typealias X = (Int) -> Int
        第一句在repl上行不通😐
        光剑书架上的书:@3Zero kotlin极简教程,正式上架预售啦!欢迎阅读,请多指教
        3Zero:@华夏商周秦汉唐宋元明清中华民国 嗯嗯,好:smile:
        光剑书架上的书:@3Zero repl 功能比较简单 去ide中吧

      本文标题:使用 Kotlin 实现 Y 组合子(Y-Combinator)

      本文链接:https://www.haomeiwen.com/subject/xvntlxtx.html