using System; using System.Collections.Generic; using System.Linq; using Mutable = System.Collections.Generic; public static class Func { // supply 1 argument to function of 2 arguments public static Func Partial(this Func f, A a) { return b => f(a, b); } // supply 1 argument to function of 3 arguments public static Func Partial(this Func f, A a) { return (b, c) => f(a, b, c); } // supply 2 arguments to function of 3 arguments public static Func Partial(this Func f, A a, B b) { return c => f(a, b, c); } // break down function of 2 arguments to require 2 successive 1-argument calls public static Func> Curry(this Func f) { return a => b => f(a, b); } // break down function of 3 arguments to require 2 successive 1-argument calls public static Func>> Curry(this Func f) { return a => b => c => f(a, b, c); } public static Func YMemoize(this Func, A, B> f) where A : IEquatable { var d = new Mutable.Dictionary(); // I'm too lazy to implement the Y combinator… Func memf = null; memf = a => { if (d.TryGetValue(a, out var b)) { return b; } else { var calcB = f(memf, a); d.Add(a, calcB); return calcB; } }; return memf; } public static Func YMemoize(this Func, A, B, C> f) where A : IEquatable where B : IEquatable => (a, b) => YMemoize, C>( (memf, ab) => f((aa, bb) => memf((aa, bb)), ab.Item1, ab.Item2)) ((a, b)); public static Func Memoize(this Func f) where A : IEquatable => YMemoize((memf, aa) => f(aa)); public static Func Memoize(this Func f) where A : IEquatable where B : IEquatable => YMemoize((memf, aa, bb) => f(aa, bb)); public static B Memoized(this Func f, A a) where A : IEquatable => f.Memoize()(a); public static C Memoized(this Func f, A a, B b) where A : IEquatable where B : IEquatable => f.Memoize()(a, b); public static B YMemoized(this Func, A, B> f, A a) where A : IEquatable => f.YMemoize()(a); public static C YMemoized(this Func, A, B, C> f, A a, B b) where A : IEquatable where B : IEquatable => f.YMemoize()(a, b); } // IEquatableFunction // Possible with if we remove the IEquatable constraint public interface IEqF {// : IEquatable> { U F(T x); } public interface IEqF {// : IEquatable> { U F(T1 x, T2 y); } [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] public class F : System.Attribute {} public class PartialEqF : IEqF, IEquatable> { private readonly IEqF f; private readonly T1 arg1; public PartialEqF(IEqF f, T1 arg1) { this.f = f; this.arg1 = arg1; hashCode = Equality.HashCode("PartialEqF", f, arg1); } public U F(T2 arg2) => f.F(arg1, arg2); public static bool operator ==(PartialEqF a, PartialEqF b) => Equality.Operator(a, b); public static bool operator !=(PartialEqF a, PartialEqF b) => !(a == b); public override bool Equals(object other) => Equality.Untyped>( this, other, x => x as PartialEqF, x => x.hashCode, x => x.f, x => x.arg1); public bool Equals(PartialEqF other) => Equality.Equatable>(this, other); private int hashCode; public override int GetHashCode() => hashCode; public override string ToString() => "Equatable function PartialEqF()"; } public static class EqFExtensionMethods { public static IEqF ImPartial(this IEqF f, T1 arg1) => new PartialEqF(f, arg1); }