Ich versuche herauszufinden, wie rekursive Funktionen (z. B. Fakultät, obwohl meine Funktionen sind viel komplizierter) in einer Zeile schreiben. Um dies zu tun, dachte ich an die Verwendung der Lambda Calculus'Y combinator.Verwendung des Y-Kombinators in C#
Hier ist die erste Definition:
Y = λf.(λx.f(x x))(λx.f(x x))
Hier ist die reduzierte Definition:
Y g = g(Y g)
Ich versuchte sie, wie dies in C# zu schreiben:
// 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
ist ein Func<dynamic, dynamic>
Ich habe zuerst versucht, es mitzu schreiben, aber that didn't work, es ist mit delegate dynamic Lambda(dynamic arg);
) von here
Mein faktorielles Lambda sieht wie folgt aus (angepasst so jetzt definiert):
Lambda factorial = f => new Lambda(n => n == 1 ? 1 : n * f(n - 1));
Und ich es so nennen:
int result = (int)(Y(factorial))(5);
jedoch In beiden Fällen (ursprüngliche und reduzierte Form des Y-Kombinators) habe ich eine Stapelüberlauf-Ausnahme. Von dem, was ich von der Verwendung der reduzierten Form vermuten kann, scheint es, als ob es am Ende ruft Y(factorial(Y(factorial(Y(factorial(...
und endet nie tatsächlich Eingabe die faktorielle Lambda.
Da ich nicht viel Erfahrung Debuggen C# Lambda-Ausdrücke kann als ich sicherlich nicht viel von dem Lambda-Kalkül verstehen, ich weiß nicht wirklich, was los ist oder wie man es beheben.
Falls es darauf ankommt, wurde diese Frage dadurch angeregt, dass Sie in C# eine einzeilige Antwort auf this question schreiben wollten.
Meine Lösung ist folgende:
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();
Mein Ziel ist es getPermutations
als einzeilige selbst rekursive Lambda zu schreiben, so dass ich es in die SelectMany
in AllSubstrings
einfügen können und einen Einzeiler ausmachen von AllSubstrings
.
Meine Fragen sind:
- Ist Y Combinator möglich in C#? Wenn ja, was mache ich bei der Implementierung falsch?
- Wenn der Y-Kombinator in C# möglich ist, wie würde ich meine Lösung für das Teilstrings-Problem (die
AllSubstrings
-Funktion) ein Einzeiler machen? - Ob der Y-Kombinator ist nicht in C# möglich, gibt es andere Methoden der Programmierung, die für One-Lining
AllSubstrings
ermöglichen würde?
'Y g = g (Y g)' ist nur gut mit fauler Bewertung. Bei der Eager-Evaluierung ist die Problemumgehung die Verwendung von Eta-Expansion: "Y g = g (\ x-> (Y g) x)". Oder vielleicht ist 'Y g x = g (\ x-> (Y g) x) x' einfacher. –
@WillNess Danke! Das hat funktioniert, als ich es als Lambda y = null geschrieben habe; y = g => g (neues Lambda (x => (y (g)) (x))) "Nun, ich schätze, das beantwortet die erste Frage. – Jashaszun
wird es Ihnen helfen, wenn ich Ihnen einen Haskell Semi-One-Liner geben würde? es ist 'concatMap Permutationen. Sequenzen 'mit' Sequenzen (x: xs) = [a | b <- Sequenzen xs, a <- [x: b, b]]; Sequenzen [] = [[]] 'und' Permutationen' eine Standardfunktion. –