using System; using System.Collections.Generic; using System.Linq; using System.Numerics; static class Func { public static Func andThen( this Func @this, Func after) => _ => after(@this(_)); } delegate OUTPUT SelfApplicable(SelfApplicable s); static class SelfApplicable { public static OUTPUT selfApply(this SelfApplicable @this) => @this(@this); } delegate FUNCTION FixedPoint(Func f); delegate OUTPUT VarargsFunction(params INPUTS[] inputs); static class VarargsFunction { public static VarargsFunction from( Func function) => function.Invoke; public static VarargsFunction upgrade( Func function) { return inputs => function(inputs[0]); } public static VarargsFunction upgrade( Func function) { return inputs => function(inputs[0], inputs[1]); } public static VarargsFunction andThen( this VarargsFunction @this, VarargsFunction after) { return inputs => after(@this(inputs)); } public static Func toFunction( this VarargsFunction @this) { return input => @this(input); } public static Func toBiFunction( this VarargsFunction @this) { return (input, input2) => @this(input, input2); } public static VarargsFunction transformArguments( this VarargsFunction @this, Func transformer) { return inputs => @this(inputs.AsParallel().AsOrdered().Select(transformer).ToArray()); } } delegate FixedPoint Y(SelfApplicable> y); static class Program { static TResult Cast(this Delegate @this) where TResult : Delegate { return (TResult)Delegate.CreateDelegate(typeof(TResult), @this.Target, @this.Method); } static void Main(params String[] arguments) { BigInteger TWO = BigInteger.One + BigInteger.One; Func toLong = x => long.Parse(x.ToString()); Func toBigInteger = x => new BigInteger(toLong(x)); /* Based on https://gist.github.com/aruld/3965968/#comment-604392 */ Y> combinator = y => f => x => f(y.selfApply()(f))(x); FixedPoint> fixedPoint = combinator.Cast>>>().selfApply(); VarargsFunction fibonacci = fixedPoint( f => VarargsFunction.upgrade( toBigInteger.andThen( n => (IFormattable)( (n.CompareTo(TWO) <= 0) ? 1 : BigInteger.Parse(f(n - BigInteger.One).ToString()) + BigInteger.Parse(f(n - TWO).ToString())) ) ) ); VarargsFunction factorial = fixedPoint( f => VarargsFunction.upgrade( toBigInteger.andThen( n => (IFormattable)((n.CompareTo(BigInteger.One) <= 0) ? 1 : n * BigInteger.Parse(f(n - BigInteger.One).ToString())) ) ) ); VarargsFunction ackermann = fixedPoint( f => VarargsFunction.upgrade( (BigInteger m, BigInteger n) => m.Equals(BigInteger.Zero) ? n + BigInteger.One : f( m - BigInteger.One, n.Equals(BigInteger.Zero) ? BigInteger.One : f(m, n - BigInteger.One) ) ).transformArguments(toBigInteger) ); var functions = new Dictionary>(); functions.Add("fibonacci", fibonacci); functions.Add("factorial", factorial); functions.Add("ackermann", ackermann); var parameters = new Dictionary, IFormattable[]>(); parameters.Add(functions["fibonacci"], new IFormattable[] { 20 }); parameters.Add(functions["factorial"], new IFormattable[] { 10 }); parameters.Add(functions["ackermann"], new IFormattable[] { 3, 2 }); functions.AsParallel().Select( entry => entry.Key + "[" + String.Join(", ", parameters[entry.Value].Select(x => x.ToString())) + "]" + " = " + entry.Value(parameters[entry.Value]) ).ForAll(Console.WriteLine); } }