我们上面定义了if函数还有一个问题,就是当参数是一个原子或者一个不涉及递归的简单函数时,一切都是正常情况下,如果涉及到递归函数就出错了,这里有一个经典的例子(definefact(lambda(n)(if(=n1)1(*n(fact(-n1))))))(fact5)然后就会出现StackOverflowError异常,我们分析一下为什么会出现异常?首先我们看一下我们自定义的if函数if(defineif(lambda(pthen_velse_v)((or(andpcar)cdr)(consthen_velse_v))))问题是怎么产生的呢?原因是if函数的p、then_v、else_v三个输入参数对应的表达式在方法调用时会被解包(执行得到结果(getAtom)),所以atom与否为什么涉及递归是功能正常吗?原因出在getAtom方法上:当o表示入参是表达式或变量时会执行eval,如果入参是原子或函数,则直接返回opprivatestaticObjectgetAtom(Objecto,Consexp,Envenv){if(IS_EXP.test(o)){returneval((Cons)o,env);}elseif(IS_SYMBOLS.test(o)){returneval(toSubCons(o,exp),env);}else{返回o;当fact函数执行时,我们会发现fact中if函数的入参else_v对应的是表达式(*n(fact(-n1))),getAtomeval会解释执行。当else_v被eval解释时,fact又会被解释执行,于是陷入了循环,出现了StackOverflowError异常。像这样(fact->if->else_v(*n(fact(-n1)))->getAtom->eval->(fact->if->else_v(*n(fact(-n1)))->getAtom->eval->(fact->...)))如何解决从刚才的分析我们知道else_v对应的表达式是在getAtom方法中执行eval的,所以只要getAtomeval没有被触发没错,这里对应else_v没有被执行,只是我们的lambda可以做到这一点(延迟加载和延迟执行),我们修改一下fact函数(definefact(lambda(n)(if(=n1)1(lambda()(*n(fact(-n1)))))))然后执行(fact5)得到结果120,一切正常,(还是可以通过中间解决的问题layer)不过这样写起来太麻烦了,我们可以写一个函数来简化操作(lambda()()),所以我们有了lazyfun函数(definelazy-fun(lambda(exp)(lambda()(exp))))然后我们将它命名为保存表达式引用的函数(definequotelazy-fun)我们的事实函数变成这样(definefact(lambda(n)(if(=n1)1(quote(*n(fact(-n1)))))))执行完(fact5),又出现了StackOverflowError。奇怪吗?(definea(lambda()(*n(fact(-n1)))))(defineIsn'tquote(lambda(exp)(lambda()(exp))))(defineb(quote(*n(fact(-n1)))))ab不等价?从数学的角度来看,它们是等价的,但是从我们程序的角度来看,它们不是同一个表达式结构。首先,让我们来看一个。在看a之前,先放上面我们的解释器解释了lambda关键字的源代码缺点args=cdr.carCons();缺点body=cdr.cdr();validateTrue(args.data().size()==x.length,cdr.parent()+"参数不一致");环境env0=环境.newInstance(env);诠释我=0;for(ObjectargName:args){env0.setEnv(((Symbols)argName),x[i]);我++;}返回applyArgs.getEval().apply(body,env0);};}再看a,上面源码cdr中a对应的是(()(*n(fact(-n1)))),x对应的是一个空数组;whileb会被定义先解释一下引号,引号cdr对应的部分是((exp)(lambda()(exp))),x对应一个元素为(*n(fact(-n1)))需要由eval解释;问题出在引号中的x上。这里和“问题是怎么产生的?”是一样的。原因是参数x中的表达式(*n(fact(-n1)))将被eval解释为输入参数。而在解释的时候又陷入了fact的循环,所以出现了StackOverflowError一般的问题到这里就结束了,但是写(lambda()(exp))还是太啰嗦了。它可以像(引用exp)一样简单吗?答案是肯定的。我们只需要自定义一个内置函数来引用privatestaticFunction
