I'm trying to figure out how to write recursive functions (e.g. factorial, although my functions are much more complicated) in one line. To do this, I thought of using the Lambda Calculus' Y combinator.
Here's the first definition:
Y = λf.(λx.f(x x))(λx.f(x x)) Here's the reduced definition:
Y g = g(Y g) I attempted to write them in C# like this:
// Original Lambda Y = f => (new Lambda(x => f(x(x)))(new Lambda(x => f(x(x))))); // Reduced Lambda Y = null; Y = g => g(Y(g)); (Lambda is a Func<dynamic, dynamic>. I first tried to typedef it with using, but that didn't work, so now it's defined with delegate dynamic Lambda(dynamic arg);)
My factorial lambda looks like this (adapted from here):
Lambda factorial = f => new Lambda(n => n == 1 ? 1 : n * f(n - 1)); And I call it like this:
int result = (int)(Y(factorial))(5); However, in both cases (original and reduced forms of the Y combinator), I end up with a stack overflow exception. From what I can surmise from using the reduced form, it seems as if it just ends up calling Y(factorial(Y(factorial(Y(factorial(... and never ends up actually entering the factorial lambda.
Since I don't have much experience debugging C# lambda expressions and I certainly don't understand much of the lambda calculus, I don't really know what's going on or how to fix it.
In case it matters, this question was inspired by trying to write a one-line answer to this question in C#.
My solution is the following:
static IEnumerable<string> AllSubstrings(string input) { return (from i in Enumerable.Range(0, input.Length) from j in Enumerable.Range(1, input.Length - i) select input.Substring(i, j)) .SelectMany(substr => getPermutations(substr, substr.Length)); } static IEnumerable<string> getPermutations(string input, int length) { return length == 1 ? input.Select(ch => ch.ToString()) : getPermutations(input, length - 1).SelectMany( perm => input.Where(elem => !perm.Contains(elem)), (str1, str2) => str1 + str2); } // Call like this: string[] result = AllSubstrings("abcd").ToArray(); My goal is to write getPermutations as a one-line self-recursive lambda so that I can insert it into the SelectMany in AllSubstrings and make a one-liner out of AllSubstrings.
My questions are the following:
- Is the Y combinator possible in C#? If so, what am I doing wrong in the implementation?
- If the Y combinator is possible in C#, how would I make my solution to the substrings problem (the
AllSubstringsfunction) a one-liner? - Whether or not the Y combinator is not possible in C#, are there any other methods of programming that would allow for one-lining
AllSubstrings?
Y g = g(Y g)is only good with lazy evaluation. With eager evalution, the workaround is to use eta-expansion:Y g = g (\x-> (Y g) x). Or maybeY g x = g (\x-> (Y g) x) xwill be easier.Lambda y = null; y = g => g(new Lambda(x => (y(g))(x)));Well I guess that answers the first question.concatMap permutations . sequenceswithsequences (x:xs) = [a | b<-sequences xs, a<-[x:b,b] ] ; sequences [] = [[]]andpermutationsa standard function.