public static ISimpleArrow Comb(ISimpleArrow a1, ISimpleArrow a2) { // Get the three generic types Type t1 = a1.a; Type t2 = a1.b; Type t3 = a2.b; // Create types for the combined function and the two source functions Type funcType = typeof(Func <,>).MakeGenericType(t1, t3); Type a1FuncType = typeof(Func <,>).MakeGenericType(t1, t2); Type a2FuncType = typeof(Func <,>).MakeGenericType(t2, t3); // Get the types of the two arrows Type a1Type = a1.GetType(); Type a2Type = a2.GetType(); // Get an arrow constructor, genericised Type[] arrowConstructorTypes = new Type[1]; arrowConstructorTypes[0] = funcType; ConstructorInfo arrowConstructor = typeof(SimpleArrow <,>).MakeGenericType(t1, t3).GetConstructor(arrowConstructorTypes); // Get the two arrows' lambda functions (type safety is cast asunder from here on...) dynamic ar1 = a1; dynamic ar2 = a2; dynamic l1 = ar1.function; dynamic l2 = ar2.function; // Get a genericised version of the CombineLambdas function Type[] types2 = new Type[3]; types2[0] = t1; types2[1] = t2; types2[2] = t3; MethodInfo combinator = typeof(LambdaCombinator).GetMethod("CombineLambdas"); combinator = combinator.MakeGenericMethod(types2); // Invoke the genericised CombineLambdas function on the extracted lambda functions dynamic[] combineArgs = new dynamic[2]; combineArgs[0] = l1; combineArgs[1] = l2; dynamic combinedFunc = combinator.Invoke(null, combineArgs); // Invoke the genericised arrow constructor on the result of the CombineLambdas function dynamic[] parameters = new dynamic[1]; parameters[0] = combinedFunc; dynamic result = arrowConstructor.Invoke(parameters); return(result); }
public void LambdaCombinatorDemo() { // Combining with messy type parameterisation Func <int, int> f1 = x => x * x; Func <int, string> f2 = x => { if (x > 5) { return("X^2 > 5!"); } else { return("X^2 < 5 :O"); } }; Func <int, string> combination = LambdaCombinator.CombineLambdas <int, int, string>(f1, f2); Console.WriteLine(combination(3)); Console.WriteLine(combination(2)); Console.WriteLine(); // Nicer combination Console.WriteLine("Now trying it with a type-parameter-free combinator..."); ISimpleArrow result = LambdaCombinator.Comb(new SimpleArrow <int, int>(f1), new SimpleArrow <int, string>(f2)); SimpleArrow <int, string> arrowResult = (SimpleArrow <int, string>)result; Console.WriteLine(arrowResult.function.Invoke(3)); // Combining in one line SimpleArrow <string, string> another = new SimpleArrow <string, string>(x => x.Length.ToString()); SimpleArrow <int, string> anotherResult = (SimpleArrow <int, string>)(LambdaCombinator.Comb( LambdaCombinator.Comb( new SimpleArrow <int, int>(f1), new SimpleArrow <int, string>(f2)), another)); Console.WriteLine(anotherResult.function.Invoke(3)); // Combining in one line without downcasting (using only arrow interfaces now) ISimpleArrow thingy = LambdaCombinator.Comb( new SimpleArrow <int, string>(x => x.ToString()), new SimpleArrow <string, int>(x => x.Length) ); Console.WriteLine(thingy.Invoke(1234)); }