驳“反驳老赵之“伪”递归”

简介: 晚上看到鹤冲天的“反驳老赵之“伪”递归”,大概看了一下,主要是反驳老赵提出的“伪”递归的概念,特别是“伪”,看起来说的都很有道理,但我个人认为,老赵说的没有错,Lambda这种看上去是递归的方式,根本不算是递归。

晚上看到鹤冲天的“反驳老赵之“伪”递归”,大概看了一下,主要是反驳老赵提出的“伪”递归的概念,特别是“伪”,看起来说的都很有道理,但我个人认为,老赵说的没有错,Lambda这种看上去是递归的方式,根本不算是递归。

我引用鹤冲天的递归概念:

一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法

我觉得这句话说的很明白,通俗点就是自己调用自己,鹤兄说递归应该不仅仅是过程还是函数,应该包括匿名方法和lambda。我同意匿名方法应该算一种,但因为是匿名方法,我们在开发中无法知道方法名,故我们无法去调用它,但lambda(和委托)算不算一种递归呢?

我们都知道lambda构建的是一个委托,委托只是对一个方法的应用,lambda表达式只是构建了一个匿名方法体,并没有去执行,只有在使用的时候根据需求来延迟加载,但其中是有陷阱的,老赵先前写了一篇“.NET中*延迟*特性的几个陷阱”,其中介绍的非常清楚。那如何反驳鹤兄呢?从他的程序来讲吧。代码:

public static readonly Func<int, int> fac = x => x <= 1 ? 1 : x * fac(x - 1);
static void Main(string[] args)
{
	int x = 5;
	Console.WriteLine(fac(x));
	Console.Read();
}

为了看清楚些,我索性执行了,照鹤兄所说,fac调用了fac就应该属于一种递归形式,但你知道它其中执行了什么吗?Look 反编译:

internal class Program
{
// Fields
	public static readonly Func<int, int> fac;
// Methods
	static Program()
	{
		if (CS$<>9__CachedAnonymousMethodDelegate1 == null)
		{
			CS$<>9__CachedAnonymousMethodDelegate1 = new Func<int, int>(null, (IntPtr) <.cctor>b__0);
		}
		fac = CS$<>9__CachedAnonymousMethodDelegate1;
	}
	private static void Main(string[] args)
	{
		Console.WriteLine(fac.Invoke(5));
		Console.Read();
	}
}

这样我们能清楚些,当我们执行委托的时候,会使用Invoke(args)来调用方法体,看清楚,是Invoke方法,并不是委托自己哦,这一点已经偏离了递归的概念了。

再来看下我们原先的递归方法:

static int  Fac(int i)
{
	return i <= 1 ? 1 : i * Fac(i - 1);
}

反编译的代码:

private static int Fac(int i)
{
	return ((i <= 1) ? 1 : (i * Fac(i)));
}

大家看清楚了吧,调用的是它自己哦。

继续说鹤兄的代码,就算鹤兄说委托调用自己委托属于一种递归,但存在着一个“延迟特性的陷阱”,这一点老赵已经说明,每一次调用的是方法体,其中的参数是从外部传进来的,并不是方法自身往下传的,老赵也在“使用Lambda表达式编写递归函数”进行了叙述,什么意思呢?就是我们在委托调用委托的时候,“递归”还没有结束的情况下,如果改变了外部这个参数值,就会影响到“递归”的结果,这也是闭包的一个陷阱。鹤兄用了readonly来让委托只读,想以此来构造一个递归的委托,但真正需要绑定的不是方法体,还需要绑定参数的,你的参数值能通过外部进行改变的,而在传统递归中,第二次调用的时候,参数值都是第一次调用说传入的,外部是无法改变的,这一点是最能说明问题所在的。

总结

太晚了,也不想写太多了,我想懂的人应该明白吧。最后说一下,虽然世界变化的很快,但编程的一些基础还是经的起考验的,并不是说有了匿名方法,委托等就能改变递归的定义,因为从它的诞生之日起,已经有很多人研究过,为什么没有把它定义为委托,肯定有一定道理在里面的。老赵说是一种“伪”递归,这是从代码层面来说的,严格来说,绝对不是递归,我也不是老赵的拥护者,老赵也说了他的SelfApplicable<T, TResult>也不是递归,所以这种驳论觉得没有什么意义。

不过有讨论总归比不讨论要好,我也不知道自己说的对不对,拿出来大家一起讨论,欢迎拍砖。

相关文章
|
关系型数据库 Serverless 分布式数据库
1.4亿人都在用|伊对APP x 阿里云PolarDB:这一对,天生配
PolarDB以其出色的性能和稳定性为伊对APP提供了强大的支持
1.4亿人都在用|伊对APP x 阿里云PolarDB:这一对,天生配
|
监控 前端开发 Cloud Native
解决WebSocket通信:前端拿不到最后一条数据的问题
解决WebSocket通信:前端拿不到最后一条数据的问题
434 0
|
移动开发 JavaScript 前端开发
如何处理 h5 使用 iframe 嵌套页面,内外 viewport 不一致导致的缩放问题?
如何处理 h5 使用 iframe 嵌套页面,内外 viewport 不一致导致的缩放问题?
2001 0
|
7月前
|
编解码 JSON 物联网
腾讯开源HunyuanVideo-I2V图生视频模型+LoRA训练脚本,社区部署、推理实战教程来啦!
继阿里的通义万相wan2.1模型之后,腾讯混元又出大招,重磅发布HunyuanVideo-I2V图生视频模型。
837 9
|
10月前
|
Ubuntu 网络协议 Linux
快速部署WSL(Windows Subsystem for Linux)
WSL提供了一种轻量级的方法,使开发者能够在Windows上无缝运行Linux环境。通过本文介绍的步骤,可以快速安装、配置和使用WSL,以满足开发和测试的需求。
1867 8
|
SQL 存储 分布式计算
大数据-157 Apache Kylin 背景 历程 特点 场景 架构 组件 详解
大数据-157 Apache Kylin 背景 历程 特点 场景 架构 组件 详解
166 9
|
11月前
|
前端开发 Java 微服务
java电商项目(一)
文档介绍了乐购商城项目的架构设计与实现过程,涵盖需求分析、系统设计、框架搭建及商品微服务的开发。项目采用B2C电商模式,前后端分离架构,使用Spring Boot、Spring Cloud等技术构建。主要内容包括 1. **需求分析与架构设计** - 描述了在Docker中启动容器、后台服务、前台门户和后台管理的具体步骤 - 详细介绍了系统的B2C电商模式及其前后端分离的设计理念 2. **技术架构** - 项目采用Spring Boot 2.1.9.RELEASE和Spring Cloud Greenwich.SR3 - 系统架构图展示了各个微服务之间的关系和交互
192 0
|
负载均衡 前端开发 安全
BFE 初探
BFE 初探
312 9
|
域名解析 缓存 运维
【域名解析DNS专栏】域名解析故障排查手册:常见问题与解决方案
【5月更文挑战第22天】【DNS故障排查手册】解决域名无法解析、速度慢、污染劫持及配置错误问题。检查网络、清理缓存、更换DNS服务器、使用HTTPS、DNSSEC及CDN。示例:使用nslookup查询域名解析。定期检查优化DNS服务器,确保稳定安全。
2959 4
【域名解析DNS专栏】域名解析故障排查手册:常见问题与解决方案
|
JavaScript 安全
下载安装 vscode(含汉化、插件的推荐和安装)
下载安装 vscode(含汉化、插件的推荐和安装)
228 0
下载安装 vscode(含汉化、插件的推荐和安装)

热门文章

最新文章