Coursera - Programming Language - 课程笔记 - Week 2

Week 2

ML变量绑定和表达式 ML Variable Bindings and Expressions

  • 注释:括号内加星号构成(* ... *)
  • 创建变量:var x = 34;,实现了一个整型变量对x的变量绑定,绑定的变量可以被复用
  • 使用文件:use “first.sml”;
  • 复用既有绑定的变量绑定将会根据动态环境中的既有绑定值判断绑定结果
  • ML具有类型检查系统,称之为静态环境,在程序执行前,会对各个变量进行类型检查
  • if条件判断语句:if ... then ... else ...;,注意then和else后的语句只会被评估其中一个,同时要求if的静态类型必须为bool,then和else的静态类型需要一致
  • 变量绑定语法:val x = e;
    • 关键字val,和符号=以及;
    • 变量x
    • 表达式e,可能有多种形式
  • 语法(Syntax)是指书写代码的标准和方式
  • 语义(Semantic)是指书写内容的含义
    • 类型检查(程序运行前)
    • 评估(程序运行时)
  • 对于变量绑定
    • 类型检查同时扩展静态环境
    • 评估表达式同时扩展动态环境

表达式规则 Rules for Expressions

  • 子表达式可以继续嵌套子表达式,因此表达式可以任意大
  • 对于每一种表达式,都需要
    • 语法
    • 类型检查规则(产生一个结果类型)
    • 评估规则(产生结果)
  • 相对比地,对变量,有
    • 语法:字符、数字或者下划线的序列,不可以数字开头
    • 类型检查(使用时):查询静态环境
    • 评估:查询动态环境
  • 加法,有
    • 语法:e1 + e2,其中e1e2分别为表达式
    • 类型检查:(对目前而言)如果两个表达式的类型都是int,那么加法的结果类型也是int,如果类型不匹配,则未通过类型检查,结果无类型
    • 评估:两个表达式结果的和
    • 表达式的结果是值
    • 所有的值都对应着表达式,但不是所有的表达式都是值
    • 每一个值都评估为“自身”,没有评估步骤(0步)
  • 条件表达式
    • 语法:if e1 then e2 else e3;,其中ifthenelse是关键字e1e2e3是子表达式
    • 类型检查:e1必须是bool类型,但e2e3必须是相同类型t(具体类型无限制),整个表达式的类型也会是t
    • 评估:首先评估e1的结果v1,如果为true,则评估e2的结果v2并作为整个表达式的结果;如果为false,则评估e3的结果v3并作为整个表达式的结果
  • 小于比较表达式(自行完成)
    • 语法:e1 < e2,其中e1e2分别为表达式
    • 类型检查:两个表达式的类型需要相同,结果类型为bool
    • 评估:分别评估两个表达式的结果v1v2,然后判断v1 < v2,若为真则结果为true,否则结果为false

REPL和错误 REPL and Errors

  • use
    • use “foo.sml”;一个非平常的表达式
    • 一次性将foo.sml中的所有绑定输入到环境中
    • 结果()被绑定到变量it,可以忽略
  • REPL
    • Read-Eval-Print-Loop
    • 视为一个运行程序的简单方式
    • 为了避免未知错误,重新use一个文件之前,应重启REPL会话
  • 错误
    • 语法错误
    • 类型检查错误
    • 评估错误(产生错误结果、产生异常或者死循环)

重影 Shadowing

  • 重影:在尝试向环境中添加一个变量时,这个变量已经存在的情况
  • 当根据既有绑定创建一个新的变量时,这个变量的实际值将会被录入动态环境,此时这个新变量的值和用于获取这个值的表达式或者既有绑定没有任何关系(同时,ML没有赋值操作)
  • 当我们有val a = 10;后再有val a = 5;这个动作并没有对a重新赋值,事实上ML并没有改变之前环境的绑定关系,而是在不同环境的一个不同的绑定映射,对原来的绑定产生了重影

非正式函数 Functions Informally

  • 函数:获得参数,计算并输出结果
  • fun pow (x : int, y : int) = <expression>...
  • 调用为pow(x,y);
  • 函数的参数可以是表达式,甚至是嵌套调用
  • 我们不需要写明函数结果类型,但是ML可以自行从函数体中推断出结果类型
  • 函数可以递归调用
  • 函数中的内容不可以引用在函数之后产生的绑定(相互调用了咋整?)
  • 递归要比循环更加清晰和好用

正式函数 Functions Formally

  • 函数:
    • 语法:fun x0 (x1 : t1, ... , xn : tn) = e
    • 评估:一个函数就是一个值(声明时,x0已经加入环境),知道调用函数时,才会评估函数体
    • 类型检查:确保函数体类型检查正确后,向函数添加x0:(t1 * ... * tn) -> t。对函数题,检查e,此时静态环境包括之前所有的绑定,参数以及函数名(递归)
  • 关于函数的类型检查:
    • 新的类型(t1 * ... * tn) -> t,右侧时结果类型,整个结果会赋予x0
    • 参数只能在e中使用
    • 评估调用时,x0的结果类型就是e的类型
  • 函数调用:
    • 语法:e0 (e1, ... en);,如果只有一个参数,括号可以省略
    • 类型检查:e0具有类型(t1 * ... * tn) -> te1具有类型t1,……,en具有类型tn,那么e0 (e1, ... en);具有类型t
    • 评估:
      • 在当前动态环境下,评估e0为一个函数fun x0 (x1 : t1, ... , xn : tn) = e
      • 在当前的动态环境下,评估参数为v1, ..., vn
      • 结果来自于对e的评估,其环境为x1->v1, ..., xn->vn的映射

对和其他元组 Pairs and Other Tuples

  • 元组(Tuple):固定数量个不同的数据项
  • 对(pair,二元组)的创建:
    • 语法:(e1, e2)
    • 评估:评估e1到值v1,评估e2到值v2,结果是(v1, v2)
    • 类型检查:如果e1类型为tae2类型为tb,那么对表达式的类型为ta * tb
  • 对的访问:
    • 语法:#1 e以及#2 e
    • 评估:评估e并返回第一个或者第二个部分
    • 类型检查:如果e有类型ta * tb,那么#1 e有类型ta#2 e有类型tb
  • 实际上,tuple是可以拥有超过两个元素的,相关的操作方式即对上述内容的泛化
  • 对和元组可以被嵌套,因此上述操作也是可以被嵌套的

列表 List

  • 元组可以嵌套并容纳各种数据,但是其大小必须是固定且已知的
  • 列表(List)可以扩展到任意个元素,但是限制为同一类型
  • 列表的创建
    • 空列表:[]
    • 一般的列表:[v1, v2, ..., vn]
    • cons连接:e1的值为ve2的值为[v1, v2, ..., vn],那么e1 :: e2的值为[v, v1, v2, ..., vn],注意类型,v的类型必须和vi是一致的,而不是e2的类型
  • 列表的访问,这里有三个标准库函数
    • null e评估为true当且仅当e评估为[]
    • 如果e评估为[v1, v2, ..., vn],那么hd e评估为v1,对空列表将产生异常
    • 如果e评估为[v1, v2, ..., vn],那么tl e评估为[v2, ..., vn],对空列表将产生异常,注意返回值为去除第一个元素的列表(有可能结果为空列表)
  • 对列表操作的类型检查
    • 对类型t,类型t list表示用于描述存储该类型的列表
    • 类型表示(列表与元组)可以嵌套
    • []是一个空列表,其类型被表示为'a list,表示为alpha列表,同时可以作为任何类型的列表做cons连接
    • null类型为'a list -> bool
    • hd类型为'a list -> 'a
    • tl类型为'a list -> 'a list
  • 通常对列表的操作会经常使用递归

let表达式 Let Expressions

  • let表达式
    • 语法:let b1 b2 ... bn in e endbi是任意的绑定,e是任意的表达式,是let表达式的表达体
    • 类型检查:按顺序检查每一个bie的类型,前面的类型可以用于后面的类型判定,e的类型将是整个表达式的类型
    • 评估:按顺序评估每一个bie在一个包含了之前绑定的动态环境中(后面的可以利用前面的);e的结果是整个let表达式的结果,所有上面的绑定将在表达体中可用,但在外部不可用
  • 给出了一种作用域(scope)的想法,let后面的绑定只在in中可用,在in中可能存在对顶级绑定的重影的情形(局部变量)
  • 像普通表达式一样,let表达式可以被放在任何地方,并且可以嵌套

嵌套函数 Nested Functions

  • 我们可以在let表达式中定义函数
  • 当我们需要一个局部函数的时候,就可以向定义局部变量一个在let表达式中定义一个局部函数
  • 使用嵌套函数的时机
    • 确保定义的这个“局部函数”确实只在特定的函数中使用
    • 处处可用可能产生滥用问题,作用域可以限制这类问题的出现
    • 可能会被改变或移除的函数,对其限制适用范围可以最小化影响

let与效率 Let and Efficiency

  • 尽量避免重复地递归

选项 Options

  • t option式一个对于任意类型t的类型
  • 创建:
    • NONE拥有类型'a option
    • SOME e,如果e拥有类型t,那么有类型t option(类比于e :: []结果的类型)
  • option不是某种类型,而是保持某种类型的类型
  • 访问:
    • isSome拥有类型'a option -> bool,对SOME返回true,对NONE返回false
    • valOf拥有类型'a option -> 'a,将option中的元素拿出来,对NONE,将产生异常

布尔值与比较运算 Booleans and Comparison Operations

  • e1 andalso e2

    • 类型检查:e1e2必须为bool
    • 评估:e1的结果如果是false,结果为false,否则取决于e2的结果
  • e1 orelse e2

    • 类型检查:同上
    • 评估:e1的结果如果是true,结果为true,否则取决于e2的结果
  • not e1

    • 类型检查:同上
    • 评估:e1的结果如果是true,结果为false,反之亦然
  • 前二者是运算符,后一者为函数

  • 上述三种运算关系都可以使用if实现

  • int类型的比较,有:= <> > < >= <=

  • 上述后四个比较运算符可用于real类型,但是不能混用

不异变 No Mutation

  • ML中,大多数数据类型不允许异变
  • 想要修改一个值,只能重新创建而非修改内容
  • 在ML中,允许出现别名的情况,但是由于不会出现“异变”的情形,因此不必考虑因为其中一个引用修改内容导致另外一个引用所指向的值发生改变的情形

总结

  • 语法:如何写下语言的结构
  • 语义:程序的意思是什么(评估规则)
  • 惯用语:对于语言中某些特性使用的典型模式
  • 库:语言提供的标准设施
  • 工具:语言的实现提供的用于简化工作的内容(实际上独立于语言的部分)
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值