如何猜出 Y combinator
先约定几个记号:
- 定义用一个冒号加等号表示“:=”,
- 表达式全等用两个等号表示“==”,
- 归约意义上的相等用一个等号表示“=”,“==”蕴涵“=”。
由于lambda演算不能定义符号,所以像这样的递归定义是不能被求值的:
f := (lambda () (f))
如何在lambda验算中实现递归?从最简单的递归函数开始。希望能带来一些启发。
寻找 \(\Omega\)
首先,我们的目标是找出一个无限循环的lambda表达式。另外额外要求这个表达式最短。
一个lambda表达式只可能有三种形式:
- 符号(x, y, z等等),
- 函数(如(lambda (x) x)),
- 应用(英文application,即函数调用,如调用函数func,参数x写作:(func x))。
第1、2种形式又称为值(value),因为他们不能被归约了。一个无限循环的表达式只能是第3种形式:
(exp1 exp2)
考虑exp1。exp1是个函数,或者能被归约成函数的应用。如果exp1是应用,那么exp1要么会归约到一个函数,要么无限循环。如果exp1无限循环,就和我们的最短假设矛盾,所以exp1会归约到一个函数。如果exp1会归约到一个函数,那么和exp1是一个函数没什么区别。简单考虑,假设exp1是个函数:
exp1 := (lambda (x) body)
那么
(exp1 exp2)
== ((lambda (x) body) exp2)
= body[x <- exp2]
为了让表达式无限循环,我们希望:
(exp1 exp2) == body[x <- exp2]
所以body应该是个应用:
body := (subexp1 subexp2)
<=> (exp1 exp2) == (subexp1[x <- exp2] subexp2[x <- exp2])
<=> exp1 == subexp1[x <- exp2] and exp2 == subexp2[x <- exp2]
从最后一个条件可以推出:
exp2 == subexp2[x <- exp2] <=> subexp2 == x
另外还能看出,表达式exp1中包含了一个和exp2相等的子表达式。满足这个条件的最简单的exp1就是和exp2相等的exp1。
exp1 == exp2
<=> subexp1[x <- exp2] == exp2
<=> subexp1 == x
综合几个条件:
exp1
== (lambda (x) body)
== (lambda (x) (subexp1 subexp2))
== (lambda (x) (x x)) exp2
== exp1
== (lambda (x) (x x))
于是我们要找的无限循环的表达式是:
((lambda (x) (x x)) (lambda (x) (x x)))
这个表达式就是lambda演算里的\(\Omega\)表达式。\(\Omega\)表达式循环的关键在于(f f)形式的表达式,即自己应用到自己。\(\Omega\)包含了三个(f f)形式的表达式。
寻找 Y combinator
一般来说,递归函数长这个样子:
target := (lambda args body[target])
body[target]的意思是一个包含target这个符号的表达式,args表示这是一个任意个数参数的函数。在这个表达式中,target是一个无约束的符号。一个包含无约束符号的表达式不能被求值。Lambda演算中约束一个符号的方法是用lambda关键字,为了让target变成约束符号,我们改写表达式:
p := (lambda (target)
(lambda args body[target]))
= (lambda (f)
(lambda args body[f]))
为了避免混淆,上面将target改名成f(\(\alpha\)归约),target仍然表示我们想要的递归函数的表达式。target和p有如下关系:
(p target)
= (lambda args body[target])
= target
顺便一提,可以看出我们在寻找的target是p的一个不动点。
接下来考虑如何找target。记得寻找\(\Omega\)的启发吗?我们猜测target是一个(g g)形式的表达式:
target == (g g)
=>
(p target) = target
<=> (p (g g)) = (g g)
<=> (g g) = (p (g g)) = ((lambda (x) (p (x x))) g)
根据最后一个条件可以看出:
g := (lambda (x) (p (x x)))
=>
target == (g g)
== ((lambda (x) (p (x x)))
(lambda (x) (p (x x))))
把p提取到参数位置:
target =
((lambda (f)
((lambda (x) (f (x x)))
(lambda (x) (f (x x))))) p) Y :=
(lambda (f)
((lambda (x) (f (x x)))
(lambda (x) (f (x x))))) target = (Y p)
这个Y就是Y combinator。
用 Y combinator 推导出 \(\Omega\)
最简单的无限循环函数是:
f := (lambda () (f))
利用Y combinator来生成这个函数的lambda表达式看看会得到什么?
(Y (lambda (f) (lambda () (f))))
= ((lambda (x) ((lambda (f) (lambda () (f))) (x x)))
(lambda (x) ((lambda (f) (lambda () (f))) (x x))))
= ((lambda (x) (lambda () ((x x))))
(lambda (x) (lambda () ((x x)))))
呼,要对齐这么多括弧真不容易。注意到(\(\eta\)归约):
(lambda () ((x x))) = (x x)
所以:
(Y (lambda (f) (lambda () (f))))
= ((lambda (x) (x x)) (lambda (x) (x x)))
如何猜出 Y combinator的更多相关文章
- Y Combinator
常见的例子 阶乘函数: fact = (a) -> if a > 0 then a * fact(a - 1) else 1 问题的提出 如上,在fact函数中调用了fact本身,无法使用 ...
- 利用Python完成一个小游戏:随机挑选一个单词,并对其进行乱序,玩家要猜出原始单词
一 Python的概述以及游戏的内容 Python是一种功能强大且易于使用的编程语言,更接近人类语言,以至于人们都说它是“以思考的速度编程”:Python具备现代编程语言所应具备的一切功能:Pytho ...
- YC(Y Combinator)斯坦福大学《如何创业》课程要点记录(粗糙)
20节课程,每节都是干货满满,时常听说理论无用,但是好的理论,绝对能帮助你少走一些弯路. YC简介: Y Combinator成立于2005年,是美国著名创业孵化器,Y Combinator扶持初创企 ...
- java基础小练习,1-打印一百次(1~10)的随机数,2-固定一个随机数(1~100),然后猜出他,3-定义以指定格式打印集合(ArrayList类型作为参数),使用{}括起来,使用@代替,分隔每个元素
推荐自己码一下,可以使用别的方法,面向对象,不需要注重过程 /* 题目:我需要打印一百次(1~10)的随机数 */ import java.util.Random; public class demo ...
- y combinator 做的一个调查_可以学习一下
RoR: 在网络营运平台企业中,RoR站稳使用率第一的位置.其用户包括:ZenPayroll (人力资源).Asile50 (零售平台).BackerKit (众筹平台).Rainforest (QA ...
- 使用Python的yield实现流计算模式
首先先提一下上一篇<如何猜出Y combinator>中用的方法太复杂了.其实在Lambda演算中实现递归的思想很简单,就是函数把自己作为第一个参数传入函数,然后后面就是简单的Lambda ...
- python 游戏(猜数字)
1. 构造猜数字核心函数 import random def guess_core(guess_min,guess_max,guess_counrt): '''猜数字核心判断函数 :param gue ...
- CF 576A 猜数
A给出一个数x,B每次猜一个y,A回答B,x是否可以被y整除,求出要猜的最小次数和需要猜的数. 枚举每个素数p,可以知道如果p^k<=n,则p^k一定需要选 Sample test(s)inpu ...
- LightOJ 1244 - Tiles 猜递推+矩阵快速幂
http://www.lightoj.com/volume_showproblem.php?problem=1244 题意:给出六种积木,不能旋转,翻转,问填充2XN的格子有几种方法.\(N < ...
随机推荐
- JConsole观察分析Java程序的运行状态
Java 自带性能监控工具:监视和管理控制台 jconsole,它可以提供 Java 某个进程的内存.线程.类加载.jvm 概要以及 MBean 等的实时信息. 通过Java SE Developme ...
- dva reduxRouter 跳转路由的参数
应该由 新页面的 this.props.location获取
- lightswitch Grid 控件添加 CheckBox 多选
ACTIVATING MULTI SELECTION WITH CHECKBOXES IN A LIGHTSWITCH GRID WITH A ONE-LINER 2013/04/02 · by pa ...
- 【JAVA WEB教程】jsp环境搭建+部署网站(eclipse+tomcat)【详细+图文】
下载tomcat7.X 下载地址为:http://tomcat.apache.org/download-70.cgi 下载完成之后就开始安装 Next I Agree 选中所有的复选框 ...
- Java设计模式学习记录-享元模式
前言 享元模式也是一种结构型模式,这篇是介绍结构型模式的最后一篇了(因为代理模式很早之前就已经写过了).享元模式采用一个共享来避免大量拥有相同内容对象的开销.这种开销最常见.最直观的就是内存损耗. 享 ...
- Jenkins持续集成学习-Windows环境进行.Net开发3
目录 Jenkins持续集成学习-Windows环境进行.Net开发3 目录 前言 目标 优化nuget包生成流程 自动触发构建 Jenkins定时轮询触发 SVN客户端钩子触发 SVN服务器钩子触发 ...
- Django之模型层(单表操作)
一.ORM简介 MVC和MTV框架中包含一个重要部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库. ORM是‘对象-关系- ...
- S3C2440 DMA 驱动示例
将 DMA 抽象为一个字符设备,在初始化函数中调用 void *dma_alloc_writecombine(struct device *dev, size_t size, dma_addr_t * ...
- Layui 获取 radio的值
var OutInvoiceType = $('#OutInvoiceType input[checked]').val(); 就可以获取到了.
- WPF 使用 Direct2D1 画图入门
本文来告诉大家如何在 WPF 使用 D2D 画图. 本文是一个系列 WPF 使用 Direct2D1 画图入门 WPF 使用 Direct2D1 画图 绘制基本图形 WPF 使用 SharpDX WP ...