Search code examples
kotliny-combinator

How to use Kotlin to Write a Y-combinator function?


Can I use Kotlin FP (Lambda, function) to write a Y-combinator function?

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

How can I do this?


Solution

  • In Kotlin, you should introduce an additional interface G, Otherwise you will get the UNCHECKED_CAST warnings, since Kotlin is a statically typed programming language rather than a dynamic language, for example:

    typealias X = (Int) -> Int
    typealias F = Function1<X, X>
    //        v-------------v--- let G reference G recursively
    interface G : Function1<G, X>
    
    //  v--- create a G from lazy blocking
    fun G(block: (G) -> X) = object : G {
        //                          v--- delegate call `block(g)` like as `g(g)`
        override fun invoke(g: G) = block(g)
    }
    
    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) } })
    

    Another version cast a Function1<G, X> to a G, so it should suppress the UNCHECKED_CAST warnings, for example:

    typealias X = (Int) -> Int
    typealias F = Function1<X, X>
    typealias G = Function1<Any, X>
    
    @Suppress("UNCHECKED_CAST")
    //                                           v--- cast `g` to `G`.
    fun Y(f: F) = (fun(g: Function1<G, X>) = g(g as G))({ g -> f { x -> g(g)(x) } })
    
    val fact = Y({ rec -> { n -> if (n == 0) 1 else n * rec(n - 1) } })