{"componentChunkName":"component---src-templates-blog-post-js","path":"/recursive-to-y-combinator/","result":{"data":{"site":{"siteMetadata":{"title":"星雨之夜"}},"markdownRemark":{"id":"f3d064e0-9188-55f1-ac92-28484db3d82a","excerpt":"停机问题 我们再来回顾一下停机问题： 是否存在一个函数 P，对于任意输入的函数 w，能够判断 w 会在有限时间内结束或者死循环。 通过前文的论述，我们已经知道这样的函数 P 是不存在的。由此可知，某些函数存在可以用语言描述却无法被程序定义的情况，以 Scheme…","html":"<h2>停机问题</h2>\n<p>我们再来回顾一下<a href=\"https://en.wikipedia.org/wiki/Halting_problem\">停机问题</a>：</p>\n<blockquote>\n<p>是否存在一个函数 P，对于任意输入的函数 w，能够判断 w 会在有限时间内结束或者死循环。</p>\n</blockquote>\n<p>通过<a href=\"/the-little-schemer-summary-9#%E5%81%9C%E6%9C%BA%E9%97%AE%E9%A2%98\">前文</a>的论述，我们已经知道这样的函数 P 是不存在的。由此可知，某些函数存在可以用语言描述却无法被程序定义的情况，以 Scheme 语言为例，即无法用 <code class=\"language-text\">(define ...)</code> 给函数命名。</p>\n<h2>递归</h2>\n<p>我们知道递归在 Scheme 中重要性是处在第一序列的。「The Little Schemer」书里，几乎所有函数都是围绕着递归思想来创建的。下面来看一个用于获取列表 l 的长度的例子：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> length\n  <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n      <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>它定义了 <code class=\"language-text\">length</code> 这个函数名称并用其进行递归操作。</p>\n<p>如果这时候告诉你，<code class=\"language-text\">(define ...)</code> 不能用了，那么还能有什么方法可以表示出 <code class=\"language-text\">length</code> 函数呢？答案是有的，不过得让我们一步步来接近它。</p>\n<h2>高阶函数</h2>\n<p>高阶函数的一个形式是：接受一个函数作为参数，返回另一个函数。在上述例子中，我们可以引入一个高阶函数，把函数 <code class=\"language-text\">length</code> 作为参数传入：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n     \t<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n     \t<span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>显然它返回的也是 <code class=\"language-text\">length</code> 函数本身，而且没有再用到 <code class=\"language-text\">(define ...)</code>。因为这个高阶函数创建了 <code class=\"language-text\">length</code> 函数（make length），所以干脆就叫它 <code class=\"language-text\">mk-length</code>。</p>\n<p>事情看起来已经符合我们的要求了，接下来似乎只要</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> length<span class=\"token punctuation\">)</span></code></pre></div>\n<p>就能得到 <code class=\"language-text\">length</code> 函数。不过传入的 <code class=\"language-text\">length</code> 参数依旧需要通过 <code class=\"language-text\">mk-length</code> 来生成，也就是：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>可以预见接下来还会有：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n  <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n      ...<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>这样下去就进入了无限循环。让我们先回到 <code class=\"language-text\">(mk-length length)</code>。</p>\n<h2>从头开始</h2>\n<p>上面 <code class=\"language-text\">length</code> 被不停创建的过程触发了无限递归，要解决这个问题，我们来做一个神奇的替换。</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> eternity\n  <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">eternity</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">eternity</code> 是我们之前创建出来的一个最简单的偏函数，并且也是无限递归的。我们用它来替换 <code class=\"language-text\">length</code>，代入 <code class=\"language-text\">(mk-length eternity)</code> 并展开：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n eternity<span class=\"token punctuation\">)</span></code></pre></div>\n<p>再创建一个高阶函数，将 <code class=\"language-text\">mk-length</code> 本身作为参数提取出来：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>那么上面这个函数是否已经创建出了 <code class=\"language-text\">length</code> 函数呢，我们代入具体的列表 l 来检验。</p>\n<p>当 l 是空列表时，进入 <code class=\"language-text\">(null? l)</code> 分支，返回值是 0，正确。</p>\n<p>当 l 是 <code class=\"language-text\">(a)</code> 这样的非空列表时，则进入 <code class=\"language-text\">else</code> 分支，但是 <code class=\"language-text\">(etertiny (quote ()))</code> 并不会返回值，函数也就不会返回正确的答案。</p>\n<p>这个函数看起来只能计算空列表的长度，称之为 <code class=\"language-text\">length0</code> 似乎更加贴切。</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> length0 <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>接下来我们可以写出 <code class=\"language-text\">length1</code>，它可以计算长度不超过 1 的列表：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> length0<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>展开：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>可以写出 <code class=\"language-text\">length2</code> 了吗？当然：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n       <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>它可以计算长度不大于 2 的列表。<code class=\"language-text\">lengthN</code> 呢？</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n       <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n         ...<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>要写 N 个 <code class=\"language-text\">mk-length</code> 了。</p>\n<p>分析上面的推导过程可知，我们现在还无法定义一个通用的 <code class=\"language-text\">length</code> 函数，使得它能够计算任意列表的长度。从另一个角度考虑，如果在上面的函数形式中，我们能够写出足够多个 <code class=\"language-text\">mk-length</code> ，那么就能计算任意列表的长度了。但是“足够多”太抽象，不同列表所要求的个数有所不同，对于一个程序或者函数来讲，这样是写不出来的。</p>\n<h2>我算我自己</h2>\n<p>我们再来看看 <code class=\"language-text\">mk-length</code>，因为它的参数是一个函数，所以理论上可以调用任意函数。我们把 <code class=\"language-text\">mk-length</code> 传给自己试试：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><code class=\"language-text\">length</code> 作为入参可以用任意字符表示，甚至是 <code class=\"language-text\">mk-length</code>：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>现在我们得出了什么呢？当传入非空列表时，else 分支的 <code class=\"language-text\">mk-length</code> 接收一个列表作为参数，但是它实际上需要的参数是函数，所以最后并不会计算出值，这就和 <code class=\"language-text\">length0</code> 一样了。同时也表明我们将 <code class=\"language-text\">mk-length</code> 传给自己其实没有改变整个函数的意义。</p>\n<p>如果我们用这个参数 <code class=\"language-text\">mk-length</code> 继续创建递归，就用 <code class=\"language-text\">eternity</code> 好了：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token comment\">; 函数一</span>\n<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n               <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span>\n                  <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>代入列表 l 看看，l 这里是 <code class=\"language-text\">(apple)</code>：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token comment\">; 第一步</span>\n<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n        <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n                <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span>\n                   <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n        <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n                <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span>\n                   <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n l<span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token comment\">; 第二步</span>\n<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n     <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n                     <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n                       <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n                         <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n                         <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n                                 <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> eternity<span class=\"token punctuation\">)</span>\n                                    <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                   eternity<span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开</span>\n                  <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n l<span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token comment\">; 第三步</span>\n<span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n     <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n                    <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n                      <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n                      <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n                              <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">eternity</span> eternity<span class=\"token punctuation\">)</span>\n                                 <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n                  <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开，这里 (cdr l) 是 (quote ())，返回 0</span>\n l<span class=\"token punctuation\">)</span></code></pre></div>\n<p>现在能够计算长度是 1 的列表了。那长度为 2 的呢？假设这时 l 是 <code class=\"language-text\">(apple banana)</code>，前三步是和上面一样的，最后可以简化成：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">eternity</span> eternity<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">quote</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>其中 <code class=\"language-text\">(eternity eternity)</code> 在无限递归，上述表达式没有返回值，所以我们算不出长度为 2 的列表。那么函数一其实就是 <code class=\"language-text\">length1</code>。问题来了，有没有什么办法可以让 <code class=\"language-text\">(eternity eternity)</code> 这个位置的递归继续下去，这样我们好像就可以计算任意长度的列表了。</p>\n<p>解决方案还是和这一节最开始用的相同方法，我们让 <code class=\"language-text\">mk-length</code> 来调用 <code class=\"language-text\">mk-length</code>：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span>\n               <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span>\n                  <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>这么做的目的是在递归即将结束的时候，又将 <code class=\"language-text\">mk-length</code> 传递给自身，确保递归的不断进行。</p>\n<p>有点激动呀，我们终于能够抛弃 <code class=\"language-text\">(define ...)</code>，仅用 lambda 表达式就写出 <code class=\"language-text\">length</code> 函数了 🥳 不过先等一下，在为胜利欢呼之前，我们来验证一下函数的正确性。</p>\n<h2>终极答案</h2>\n<p>首先我们用高阶函数把 <code class=\"language-text\">(mk-length mk-length)</code> 语句提取出来，让函数更加清晰：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n          <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>第 4 到 8 行长得就很像一开始的 <code class=\"language-text\">mk-length</code>，这么一来就舒服了。之后当然是用具体的列表来测试啦，依旧借用 <code class=\"language-text\">(apple)</code>。要计算 <code class=\"language-text\">(length (quote (apple)))</code> 的值需要先展开 <code class=\"language-text\">length</code> 也就是上面这个函数，我们来试试吧。</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n          <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开</span>\n   <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n          <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n           <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n           <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开</span>\n    <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n         <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n           <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n           <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n        <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n            <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">; 代入展开...</span>\n     <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n            <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>咦等等，这么一级级展开完全没有尽头，我们只是不停地把 <code class=\"language-text\">mk-length</code> 应用到它自己身上，周而复始。<code class=\"language-text\">(mk-length mk-length)</code> 本来期待它返回一个函数的，现在再也返回不了了。这可怎么办，胜利道路严重受阻。</p>\n<p>不要方，我们还有一个武器——<a href=\"https://en.wikipedia.org/wiki/Lazy_evaluation\">惰性求值</a>，它的思想简单来说就是使表达式在被用到的时候才求值。在我们的需求里面就是对 <code class=\"language-text\">(mk-length mk-length)</code> 惰性求值，前面的运算里面不对它进行展开。</p>\n<p>如何做？我们考虑到 <code class=\"language-text\">(mk-length mk-length)</code> 返回的函数在理论条件下就是 <code class=\"language-text\">length</code>，它是一个单参数函数。那么我们构造一个单参数函数，它可以做到惰性求值：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p><a href=\"https://en.wikipedia.org/wiki/Lambda_calculus\">Lambda 演算</a>中的第三条 η-变换规则规定到：对于任一给定的参数，当且仅当两个函数得到的结果都一致，则它们将被视同为一个函数。即如果对于给定的 l，<code class=\"language-text\">((mk-length mk-length) l)</code> 和 <code class=\"language-text\">((lambda (x) ((mk-length mk-length) x)) l)</code> 的值都相同，那么就说这两个函数是等价的。显然他们就是同一个函数。那么做完替换之后长这样：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n          <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n          <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>我们再构建一个高阶函数，移出第 4 到 8 行长得像 <code class=\"language-text\">mk-length</code> 的部分，作为参数：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">le</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">le</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">l</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token keyword\">cond</span>\n       <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token builtin\">null?</span> l<span class=\"token punctuation\">)</span> <span class=\"token number\">0</span><span class=\"token punctuation\">)</span>\n       <span class=\"token punctuation\">(</span><span class=\"token keyword\">else</span> <span class=\"token punctuation\">(</span><span class=\"token function\">add1</span> <span class=\"token punctuation\">(</span><span class=\"token function\">length</span> <span class=\"token punctuation\">(</span><span class=\"token builtin\">cdr</span> l<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>🎉 大功告成！以上就是我们不用 <code class=\"language-text\">(define ...)</code> 而写出的 <code class=\"language-text\">length</code> 最终版本。不容易啊。</p>\n<h2>Y 组合子</h2>\n<p>我们把上面函数调用 <code class=\"language-text\">mk-length</code> 的逻辑部分剥离出来：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">le</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">le</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span>\n           <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> mk-length<span class=\"token punctuation\">)</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>简化一下：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">le</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">f</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span><span class=\"token function\">f</span> f<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n   <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">f</span><span class=\"token punctuation\">)</span>\n     <span class=\"token punctuation\">(</span><span class=\"token function\">le</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">lambda</span> <span class=\"token punctuation\">(</span><span class=\"token function\">x</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token function\">f</span> f<span class=\"token punctuation\">)</span> x<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>这玩意儿就叫应用序 Y 组合子（applicative-order Y combinator）！</p>\n<p>仔细体会整个过程，在不给函数命名的情况下，我们最终却实现了这个递归函数。实际上正是 Y 组合子做了这件极其伟大的事情——实现递归。</p>\n<h3>补充：不动点组合子</h3>\n<p>这里我们先引入不动点的概念：对于函数 f，如果存在变量 x，有 f(x) = x，此时就说 x 是函数 f 的不动点。</p>\n<p>我们来看看 <code class=\"language-text\">mk-length</code> 的不动点 <code class=\"language-text\">fixed-point</code> 是什么。</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> fixed-point\n  <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> fixed-point<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>那么可以替换函数体中的 <code class=\"language-text\">fixed-point</code> 为 <code class=\"language-text\">(mk-length fixed-point)</code>：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> fixed-point\n  <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> fixed-point<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> fixed-point\n  <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span> fixed-point<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">define</span> fixed-point\n  <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n    <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n      <span class=\"token punctuation\">(</span><span class=\"token function\">mk-length</span>\n        ...<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>看上去很眼熟对不对？所以 <code class=\"language-text\">mk-length</code> 的不动点就是我们想要的 <code class=\"language-text\">length</code>。于是求 <code class=\"language-text\">length</code> 的问题就转化为：有没有这样一个函数 <code class=\"language-text\">calc-fixed-point</code>，代入参数 <code class=\"language-text\">mk-length</code>，然后得到 <code class=\"language-text\">mk-length</code> 的不动点：</p>\n<div class=\"gatsby-highlight\" data-language=\"scheme\"><pre class=\"language-scheme\"><code class=\"language-scheme\"><span class=\"token punctuation\">(</span><span class=\"token function\">calc-fixed-point</span> mk-length<span class=\"token punctuation\">)</span> = length</code></pre></div>\n<p>又是一个眼熟的表达式，<code class=\"language-text\">calc-fixed-point</code> 看起来就是我们上面所得到的 Y 组合子，它可以计算参数的不动点。所以有时它又被称为不动点组合子。</p>\n<p>关于 Lambda 演算、组合子、由不动点推导 Y 组合子等知识点，本文暂不作讨论。我光是看明白「The Little Schemer」第九章里推导 Y 组合子的过程，头就已经大了好几圈，头发也多掉了好几<del>万</del>根，就像书里说得那样。文章也无法避免由主观臆断而产生的概念性或者推导上的错误，欢迎指正。</p>\n<h2>参考链接</h2>\n<ol>\n<li>「The Little Schemer：递归与函数式的奥妙」第 9 章</li>\n<li><a href=\"https://mvanier.livejournal.com/2897.html\">The Y Combinator</a></li>\n<li><a href=\"https://stackoverflow.com/q/48018651/3134870\">Little Schemer: why wrap (mk-length mk-length) into a function?</a></li>\n<li><a href=\"https://coderemixer.com/2018/12/07/y-combinator-in-ten-minutes/\">十分钟速通 Y Combinator</a></li>\n<li><a href=\"http://www.cppblog.com/huaxiazhihuo/archive/2013/07/11/201689.html\">scheme 下的停机问题和 Y 组合子</a></li>\n<li><a href=\"https://www.zhihu.com/question/21099081\">Y 不动点组合子用在哪里？</a></li>\n<li><a href=\"https://en.wikipedia.org/wiki/Lambda_calculus\">Lambda 演算 - 维基百科</a></li>\n<li><a href=\"https://en.wikipedia.org/wiki/Fixed-point_combinator\">不动点组合子 - 维基百科</a></li>\n</ol>","frontmatter":{"title":"从递归到 Y 组合子","date":"2019 年 01 月 29 日","description":"本文是对「The Little Schemer」第九章后半段的再推导，也是对我学习 Scheme 过程的补充。主要讲述匿名函数如何递归，并由此引出 Y 组合子。"}}},"pageContext":{"slug":"/recursive-to-y-combinator/","previous":{"fields":{"slug":"/the-little-schemer-summary-9/"},"frontmatter":{"title":"The Little Schemer 知识点整理（九）：……周而复始……"}},"next":null}}}