形式语义03 Lambda
\(\lambda\)-calculus讲了一点点,后面的下次再补...
Background
首先这是一种编程语言,在1930s被Alonzo Church和Stephen Cole Kleene发明(两位都是听说过的明星人物)
还是一种计算模型,在1937年被Alan Turing证明其和图灵机的表达能力等价(这位更是重量级)
\(\lambda\) 演算是函数式编程的基础,同时它简单的特点也使得很适合用于研究PL的各个领域(回忆IDFS中的\(\lambda\) 表达式作为transfer function)
Syntax
定义 \(\mathcal V\) 是无穷变量集合,\(\Sigma=\mathcal V\cup\left\{(,),\lambda,.\right\}\) 为字符集,那么定义一个term为\(\Sigma\)上的有穷串
\(\lambda\) calculus term组成的集合 \(\Lambda\subseteq \Sigma^*\) 定义为满足如下条件的最小集合:
- 若 \(x\in\mathcal V\),那么 \(x\in\Lambda\)
- 若 \(M,N\in\Lambda\),那么 \((MN)\in\Lambda\)
- 若 \(x\in\mathcal V\) 且 \(M\in\Lambda\),那么 \((\lambda x.M)\in\Lambda\),此时称 \(M\) 为这个term的body
上面三种形式分别叫做variable、application、\(\lambda\) abstraction(function)
为了简略(这也太简略了),有一些约定俗成的优先级和结合律:
- 最外层括号可以省略不写,例如 \((\lambda x.x^2)=\lambda x.x^2\)
- Application形式是左结合的,即 \(f\;x\;y\;z=((f\;x)\;y)\;z\)
- 一个\(\lambda\)的约束范围(scope)向右延伸,body的范围尽可能长。例如 \(\lambda x. x+y=\lambda x.(x+y)\neq(\lambda x. x)+y\)
- 多个\(\lambda\) 可以写在一起。例如 \(\lambda x.\lambda y.\lambda z.=\lambda xyz.\)
Semantics
Bound & Free Variables
对于一个形如 \(\lambda x.N\) 的term,我们就说 \(N\) 中出现的 \(x\) 都被绑定(binding)到了 \(\lambda x.\) 上
注意绑定是可以嵌套的,例如 \(\lambda x. (\lambda f.\lambda x.f\; x)+x\),最里面的 \(x\) 被绑定到了第二个 \(\lambda x.\),而最后一个 \(x\) 则被绑定到了第一个 \(\lambda x.\) 这个规则和C的作用域是很相似的
如果一个变量没有被绑定,就被称为自由变量(free variables)
一个bound variable是可以被换名字而不改变term的含义的,类似于C function中形参的名字其实是任意的(但仍然有限制,后面会说)。而free variable则不能随意换名字。因此我们主要关注一个term \(M\) 中具体的free variables有哪些,用 \(FV(M)\) 这个记号来表示
容易有如下规则:
- \(FV(x)=\left\{\;x\;\right\}\)
- \(FV(\lambda x.M)=FV(M)-\left\{\;x\;\right\}\)
- \(FV(M N)=FV(M)\cup FV(N)\)
也就是通过表达式的结构来递归求值
Substitution
这里的substitution和直接替换是有区别的
我们用 \(M[x/y]\) 或者 \(M\left\{x/y\right\}\) 来表示用 \(x\) 替换掉term \(M\) 中的 \(y\) 的结果,并把一次substitution记作 \(M\rightarrow M[x/y]\)
考虑如下C代码
int x=1;
int y=2;
int foo(int z) {
return x + y + z;
}
这里第5行中,x,y
是free variable,z
被绑定到形参int z
前面说到对函数的形参可以任意换名但是有条件。考虑以下三种情况:
- 作替换\([x/z]\),这时候第5行变为
return x + y + x;
,且这里的两个x
都被绑定到形参int x
上(形参也被替换了),含义和原文显然是不同的 - 作替换\([u/z]\),这时候
u
从未出现过(称为fresh variable),这个替换就没有任何问题 - 作替换\([z/x]\),这时候
x
从free variable变成了bound variable,含义也发生了变化
基于如上考虑,我们给出substitution的递归定义:
- \(x[N/x]\overset{\text{def}} =N\)
- \(y[N/x]\overset{\text{def}}=x\)
- \((M N)[P/x]=(M[P/x])(N[P/x])\)
- \(\lambda x.M[N/x]=\lambda x.M\)
- 若 \(y\not\in FV(N)\),那么 \((\lambda y.M)[N/x]=\lambda y.(M[N/x])\)
- 若 \(y\in FV(N)\),那么 \((\lambda y.M)[N/x]=\lambda z.(M[z/y][N/x])\)
1234都好理解,主要说说56
5的意思是如果 \([N/x]\) 不会引入新的 与当前形参重名的free variable,那么就直接换
6的意思是如果非要换,那么就得先把 \(M\) 中被绑定到当前 \(\lambda y.\) 上的 \(y\) 都换成一个fresh variable \(z\),此时就规约成5的情况了
\(\beta\)-reduction
这个主要用于application求值的时候,递归定义如下:
- \((\lambda x. M)N\rightarrow M[N/x]\),意思是一个application就是一个substitution
- 如果 \(M\rightarrow M'\),那么 \(\lambda x.M\rightarrow\lambda x.M'\)
- 如果 \(M\rightarrow M'\),那么 \(M N\rightarrow M' N\)
- 同理若 \(N\rightarrow N'\),那么 \(MN\rightarrow MN'\)
本文来自博客园,作者:jjppp。本博客所有文章除特别声明外,均采用CC BY-SA 4.0 协议
原文地址:https://www.cnblogs.com/jjppp/p/15292808.html
- 线程池
- hbase 部署
- Hadoop源码系列(一)FairScheduler申请和分配container的过程
- MOTS攻击之TCP攻击
- iOS学习——获取当前最顶层的ViewController
- 中国深圳一家厂商的智能摄像头曝出漏洞:至少 17.5 万设备可被远程攻击
- iOS学习——Xcode9上传项目到GitHub
- 手把手教你编写一个简单的PHP模块形态的后门
- 如何将简单的Shell转换成为完全交互式的TTY
- 如何使用HackRF做一个简单的IMSI捕获器
- 联想Z470黑化之路:硬件升级还能刷苹果Mac系统!
- 渗透测试TIPS之删除、伪造Linux系统登录日志
- 1分钟懂awk-技不在深,够用就行
- RChain节点通信机制
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Yii2框架加载css和js文件的方法分析
- php 与 nginx 的处理方式及nginx与php-fpm通信的两种方式
- python如何求圆的面积
- php实现微信公众号企业转账功能
- PHP通过调用新浪API生成t.cn格式短网址链接的方法详解
- Python之Matplotlib文字与注释的使用方法
- Python实现图片查找轮廓、多边形拟合、最小外接矩形代码
- python中return如何写
- PHP钩子实现方法解析
- 浅谈numpy中函数resize与reshape,ravel与flatten的区别
- PHP文件类型检查及fileinfo模块安装使用详解
- PHP封装的分页类与简单用法示例
- ThinkPHP3.2框架自带分页功能实现方法示例
- PHP获取访问设备信息的方法示例
- PHP实现微信提现功能