在 C# 中使用 Y 组合器
Using the Y Combinator in C#
我正在尝试找出如何在一行中编写递归函数(例如阶乘,尽管我的函数要复杂得多)。为此,我想到了使用 Lambda Calculus' Y combinator.
这是第一个定义:
Y = λf.(λx.f(x x))(λx.f(x x))
这是简化的定义:
Y g = g(Y g)
我试图用 C# 编写它们,如下所示:
// 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
是一个 Func<dynamic, dynamic>
。我首先尝试用 using
对它进行类型定义,但是 that didn't work,所以现在它是用 delegate dynamic Lambda(dynamic arg);
定义的)
我的阶乘 lambda 看起来像这样(改编自 here):
Lambda factorial = f => new Lambda(n => n == 1 ? 1 : n * f(n - 1));
我这样称呼它:
int result = (int)(Y(factorial))(5);
然而,在这两种情况下(Y 组合器的原始形式和简化形式),我都以堆栈溢出异常结束。从我使用简化形式可以推测的情况来看,它似乎只是结束调用 Y(factorial(Y(factorial(Y(factorial(...
而实际上从未结束 entering 阶乘 lambda。
由于我没有太多调试 C# lambda 表达式的经验而且我当然不太了解 lambda 演算,所以我真的不知道发生了什么或如何修复它。
以防万一,这个问题的灵感来自试图用 C# 编写 的单行答案。
我的解决方案如下:
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();
我的目标是将 getPermutations
编写为单行自递归 lambda,这样我就可以将它插入到 AllSubstrings
中的 SelectMany
中,并生成一个单行输出AllSubstrings
.
我的问题如下:
- 在 C# 中可以使用 Y 组合器吗?如果是这样,我在实施中做错了什么?
- 如果 Y 组合子 在 C# 中是可能的,我将如何使我对子字符串问题(
AllSubstrings
函数)的解决方案成为单行代码?
- 无论 Y 组合子是否 not 在 C# 中是可能的,是否有任何其他编程方法允许单行
AllSubstrings
?
这是我在 c# 中使用的 Y 组合器的实现:
public delegate T S<T>(S<T> s);
public static T U<T>(S<T> s)
{
return s(s);
}
public static Func<A, Z> Y<A, Z>(Func<Func<A, Z>, Func<A, Z>> f)
{
return U<Func<A, Z>>(r => a => f(U(r))(a));
}
我可以这样使用它:
var fact = Y<int, int>(_ => x => x == 0 ? 1 : x * _(x - 1));
var fibo = Y<int, int>(_ => x => x <= 1 ? 1 : _(x - 1) + _(x - 2));
这真的让我感到害怕,所以我将把你问题的下两部分留给你,以此为起点。
我已经破解了这个函数。
这里是:
var allsubstrings =
Y<string, IEnumerable<string>>
(_ => x => x.Length == 1
? new [] { x }
: Enumerable
.Range(0, x.Length)
.SelectMany(i =>
_(x.Remove(i, 1))
.SelectMany(z => new [] { x.Substring(i, 1) + z, z }))
.Distinct());
当然,你运行它是这样的:
allsubstrings("abcd");
我从中得到这个结果:
abcd
bcd
acd
cd
abd
bd
ad
d
abdc
bdc
adc
dc
abc
bc
ac
c
acbd
cbd
acdb
cdb
adb
db
acb
cb
ab
b
adbc
dbc
adcb
dcb
bacd
bad
badc
bac
bcad
cad
bcda
cda
bda
da
bca
ca
ba
a
bdac
dac
bdca
dca
cabd
cadb
cab
cbad
cbda
cba
cdab
dab
cdba
dba
dabc
dacb
dbac
dbca
dcab
dcba
你的问题中的非 Y-Combinator 代码似乎遗漏了一堆排列。
我正在尝试找出如何在一行中编写递归函数(例如阶乘,尽管我的函数要复杂得多)。为此,我想到了使用 Lambda Calculus' Y combinator.
这是第一个定义:
Y = λf.(λx.f(x x))(λx.f(x x))
这是简化的定义:
Y g = g(Y g)
我试图用 C# 编写它们,如下所示:
// 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
是一个 Func<dynamic, dynamic>
。我首先尝试用 using
对它进行类型定义,但是 that didn't work,所以现在它是用 delegate dynamic Lambda(dynamic arg);
定义的)
我的阶乘 lambda 看起来像这样(改编自 here):
Lambda factorial = f => new Lambda(n => n == 1 ? 1 : n * f(n - 1));
我这样称呼它:
int result = (int)(Y(factorial))(5);
然而,在这两种情况下(Y 组合器的原始形式和简化形式),我都以堆栈溢出异常结束。从我使用简化形式可以推测的情况来看,它似乎只是结束调用 Y(factorial(Y(factorial(Y(factorial(...
而实际上从未结束 entering 阶乘 lambda。
由于我没有太多调试 C# lambda 表达式的经验而且我当然不太了解 lambda 演算,所以我真的不知道发生了什么或如何修复它。
以防万一,这个问题的灵感来自试图用 C# 编写
我的解决方案如下:
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();
我的目标是将 getPermutations
编写为单行自递归 lambda,这样我就可以将它插入到 AllSubstrings
中的 SelectMany
中,并生成一个单行输出AllSubstrings
.
我的问题如下:
- 在 C# 中可以使用 Y 组合器吗?如果是这样,我在实施中做错了什么?
- 如果 Y 组合子 在 C# 中是可能的,我将如何使我对子字符串问题(
AllSubstrings
函数)的解决方案成为单行代码? - 无论 Y 组合子是否 not 在 C# 中是可能的,是否有任何其他编程方法允许单行
AllSubstrings
?
这是我在 c# 中使用的 Y 组合器的实现:
public delegate T S<T>(S<T> s);
public static T U<T>(S<T> s)
{
return s(s);
}
public static Func<A, Z> Y<A, Z>(Func<Func<A, Z>, Func<A, Z>> f)
{
return U<Func<A, Z>>(r => a => f(U(r))(a));
}
我可以这样使用它:
var fact = Y<int, int>(_ => x => x == 0 ? 1 : x * _(x - 1));
var fibo = Y<int, int>(_ => x => x <= 1 ? 1 : _(x - 1) + _(x - 2));
这真的让我感到害怕,所以我将把你问题的下两部分留给你,以此为起点。
我已经破解了这个函数。
这里是:
var allsubstrings =
Y<string, IEnumerable<string>>
(_ => x => x.Length == 1
? new [] { x }
: Enumerable
.Range(0, x.Length)
.SelectMany(i =>
_(x.Remove(i, 1))
.SelectMany(z => new [] { x.Substring(i, 1) + z, z }))
.Distinct());
当然,你运行它是这样的:
allsubstrings("abcd");
我从中得到这个结果:
abcd
bcd
acd
cd
abd
bd
ad
d
abdc
bdc
adc
dc
abc
bc
ac
c
acbd
cbd
acdb
cdb
adb
db
acb
cb
ab
b
adbc
dbc
adcb
dcb
bacd
bad
badc
bac
bcad
cad
bcda
cda
bda
da
bca
ca
ba
a
bdac
dac
bdca
dca
cabd
cadb
cab
cbad
cbda
cba
cdab
dab
cdba
dba
dabc
dacb
dbac
dbca
dcab
dcba
你的问题中的非 Y-Combinator 代码似乎遗漏了一堆排列。