一个卷积函数可以写成尾递归形式吗?
Can a convolution function written in tail recursive form?
我有一个函数想以尾递归形式编写。该函数通过滚动 s
面骰子 n
次来计算获得 k
总和的方法数。我在 this answer 上看到了这个函数的数学解法。具体如下:
我在 R 中的参考递归实现是:
sum_ways <- function(n_times, k_sum, s_side) {
if (k_sum < n_times || k_sum > n_times * s_side) {
return(0)
} else if (n_times == 1) {
return(1)
} else {
sigma_values <- sapply(
1:s_side,
function(j) sum_ways(n_times - 1, k_sum - j, s_side)
)
return(sum(sigma_values))
}
}
我曾尝试按照从 this answer 中学到的方法,以延续传递的方式重写该函数,但没有成功。有没有办法以尾递归形式编写此函数?
编辑
我知道 R 没有针对尾递归进行优化。我的问题不是特定于 R 的,欢迎使用任何其他语言的解决方案。即使它是一种不针对尾递归进行优化的语言。
试试这个(递归,如果我们想要尾递归版本,我们需要考虑线性递归关系):
f <- function(n, k) {
if (n == 1) { # base case
return(ifelse(k<=6, 1, 0))
} else if (k > n*6 | k < n) { # some validation
return(0)
}
else {
# recursive calls, f(1,j)=1, 1<=j<=6, otherwise 0
return(sum(sapply(1:min(k-n+1, 6), function(j) f(n-1,k-j))))
}
}
sapply(1:13, function(k) f(2, k))
# [1] 0 1 2 3 4 5 6 5 4 3 2 1 0
sapply
不是continuation-passing样式,所以你必须替换它。
这是 Python 中延续传递样式的翻译(另一种 没有 具有适当尾调用的语言):
def sum_ways_cps(n_times, k_sum, s_side, ctn):
"""Compute the number of ways to get the sum k by rolling an s-sided die
n times. Then pass the answer to ctn."""
if k_sum < n_times or k_sum > n_times * s_side:
return ctn(0)
elif n_times == 1:
return ctn(1)
else:
f = lambda j, ctn: sum_ways_cps(n_times - 1, k_sum - j, s_side, ctn)
return sum_cps(1, s_side + 1, 0, f, ctn)
def sum_cps(j, j_max, total_so_far, f, ctn):
"""Compute the sum of f(x) for x=j to j_max.
Then pass the answer to ctn."""
if j > j_max:
return ctn(total_so_far)
else:
return f(j, lambda result: sum_cps(j + 1, j_max, total_so_far + result, f, ctn))
sum_ways_cps(2, 7, 6, print) # 6
我有一个函数想以尾递归形式编写。该函数通过滚动 s
面骰子 n
次来计算获得 k
总和的方法数。我在 this answer 上看到了这个函数的数学解法。具体如下:
我在 R 中的参考递归实现是:
sum_ways <- function(n_times, k_sum, s_side) {
if (k_sum < n_times || k_sum > n_times * s_side) {
return(0)
} else if (n_times == 1) {
return(1)
} else {
sigma_values <- sapply(
1:s_side,
function(j) sum_ways(n_times - 1, k_sum - j, s_side)
)
return(sum(sigma_values))
}
}
我曾尝试按照从 this answer 中学到的方法,以延续传递的方式重写该函数,但没有成功。有没有办法以尾递归形式编写此函数?
编辑
我知道 R 没有针对尾递归进行优化。我的问题不是特定于 R 的,欢迎使用任何其他语言的解决方案。即使它是一种不针对尾递归进行优化的语言。
试试这个(递归,如果我们想要尾递归版本,我们需要考虑线性递归关系):
f <- function(n, k) {
if (n == 1) { # base case
return(ifelse(k<=6, 1, 0))
} else if (k > n*6 | k < n) { # some validation
return(0)
}
else {
# recursive calls, f(1,j)=1, 1<=j<=6, otherwise 0
return(sum(sapply(1:min(k-n+1, 6), function(j) f(n-1,k-j))))
}
}
sapply(1:13, function(k) f(2, k))
# [1] 0 1 2 3 4 5 6 5 4 3 2 1 0
sapply
不是continuation-passing样式,所以你必须替换它。
这是 Python 中延续传递样式的翻译(另一种 没有 具有适当尾调用的语言):
def sum_ways_cps(n_times, k_sum, s_side, ctn):
"""Compute the number of ways to get the sum k by rolling an s-sided die
n times. Then pass the answer to ctn."""
if k_sum < n_times or k_sum > n_times * s_side:
return ctn(0)
elif n_times == 1:
return ctn(1)
else:
f = lambda j, ctn: sum_ways_cps(n_times - 1, k_sum - j, s_side, ctn)
return sum_cps(1, s_side + 1, 0, f, ctn)
def sum_cps(j, j_max, total_so_far, f, ctn):
"""Compute the sum of f(x) for x=j to j_max.
Then pass the answer to ctn."""
if j > j_max:
return ctn(total_so_far)
else:
return f(j, lambda result: sum_cps(j + 1, j_max, total_so_far + result, f, ctn))
sum_ways_cps(2, 7, 6, print) # 6