Task: Church numerals





Java: package lvijay;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;

public class Church {
    public static interface ChurchNum extends Function<ChurchNum, ChurchNum> {
    }

    public static ChurchNum zero() {
        return f -> x -> x;
    }

    public static ChurchNum next(ChurchNum n) {
        return f -> x -> f.apply(n.apply(f).apply(x));
    }

    public static ChurchNum plus(ChurchNum a) {
        return b -> f -> x -> b.apply(f).apply(a.apply(f).apply(x));
    }

    public static ChurchNum pow(ChurchNum m) {
        return n -> m.apply(n);
    }

    public static ChurchNum mult(ChurchNum a) {
        return b -> f -> x -> b.apply(a.apply(f)).apply(x);
    }

    public static ChurchNum toChurchNum(int n) {
        if (n <= 0) {
            return zero();
        }
        return next(toChurchNum(n - 1));
    }

    public static int toInt(ChurchNum c) {
        AtomicInteger counter = new AtomicInteger(0);
        ChurchNum funCounter = f -> {
            counter.incrementAndGet();
            return f;
        };

        plus(zero()).apply(c).apply(funCounter).apply(x -> x);

        return counter.get();
    }

    public static void main(String[] args) {
        ChurchNum zero  = zero();
        ChurchNum three = next(next(next(zero)));
        ChurchNum four  = next(next(next(next(zero))));

        System.out.println("3+4=" + toInt(plus(three).apply(four))); 
        System.out.println("4+3=" + toInt(plus(four).apply(three))); 

        System.out.println("3*4=" + toInt(mult(three).apply(four))); 
        System.out.println("4*3=" + toInt(mult(four).apply(three))); 

        
        System.out.println("3^4=" + toInt(pow(four).apply(three))); 
        System.out.println("4^3=" + toInt(pow(three).apply(four))); 

        System.out.println("  8=" + toInt(toChurchNum(8))); 
    }
}



Python: 

from itertools import repeat
from functools import reduce




def churchZero():
    
    return lambda f: identity


def churchSucc(cn):
    
    return lambda f: compose(f)(cn(f))


def churchAdd(m):
    
    return lambda n: lambda f: compose(m(f))(n(f))


def churchMult(m):
    
    return lambda n: compose(m)(n)


def churchExp(m):
    
    return lambda n: n(m)


def churchFromInt(n):
    
    return lambda f: (
        foldl
        (compose)
        (identity)
        (replicate(n)(f))
    )



def churchFromInt_(n):
    
    if 0 == n:
        return churchZero()
    else:
        return churchSucc(churchFromInt(n - 1))


def intFromChurch(cn):
    
    return cn(succ)(0)




def main():
    'Tests'

    cThree = churchFromInt(3)
    cFour = churchFromInt(4)

    print(list(map(intFromChurch, [
        churchAdd(cThree)(cFour),
        churchMult(cThree)(cFour),
        churchExp(cFour)(cThree),
        churchExp(cThree)(cFour),
    ])))





def compose(f):
    
    return lambda g: lambda x: g(f(x))



def foldl(f):
    
    def go(acc, xs):
        return reduce(lambda a, x: f(a)(x), xs, acc)
    return lambda acc: lambda xs: go(acc, xs)



def identity(x):
    
    return x



def replicate(n):
    
    return lambda x: repeat(x, n)



def succ(x):
    
    return 1 + x if isinstance(x, int) else (
        chr(1 + ord(x))
    )


if __name__ == '__main__':
    main()