【Scheme】Scheme 编程学习 (二) —— 基础


文接前一节内容 :
【Scheme】Scheme 编程学习(一) —— 概述

本文章可以跟视频课程一起看,做了一些补充说明

原视频地址:

  • Bilibili https://www.bilibili.com/video/BV1Kt411R7Wf/?p=2&spm_id_from=pageDriver

文章目录

  • 【Scheme】Scheme 编程学习 (二) —— 基础
    • I - 概述
    • II - 数据结构
      • 2.1 - 点对 Pairs
      • 2.2 - 表 Lists
        • 2.2.1 - 单元素表和空表
        • 2.2.2 - 复合操作
        • 2.2.3 - list 过程
    • III - Loops
    • IV - 两种特殊的过程
      • 4.1 - Map
      • 4.2 - Fold
    • V - 注意事项

I - 概述


本节主要介绍 Scheme 的基础,包含以下四个部分:

  • 两种数据结构点对 (Pairs) 和 表 (Lists),以及如何创建
  • Loops
  • 两种特殊的过程 (Procedures) Map 与 Fold
  • 注意

Scheme 是一种函数式编程语言,什么意思呢?就是说它的参数可以为函数,返回值为函数,而且必须有返回值,若没有返回值,则接连的函数式无法继续执行下去。前一个函数的结果为后一个函数的参数。

而且 Scheme 是一种脚本语言,也就是类似 Python 需要解释器。不同于编译语言和伪编译语言。

II - 数据结构

2.1 - 点对 Pairs


(cons 1 2)

上述代码是调用过程 (Procedure) 的方式,( + 过程名称 + 参数 + ) , 过程与函数类似,调用过程可以理解为调用函数,这里过程名为 cons 用于创建点对,此调用结果为:

(1 . 2)

也可以使用嵌套的过程

(cons (cons 1 2) 3)
; ((1 . 2) . 3)

定义符号 (Symbol),使用 define 过程,定义符号 foo 为点对 (1 . 2)

(define foo (cons 1 2))
foo
; 检查 foo 输出 (1 . 2)

点对包含两个域 carcdr

有两个同名的过程:
car 获取数据对象中的第一个元素
cdr 获取数据对象中的第二个元素

(car foo)
; 1
(cdr foo)
; 2

符号 foo 中第一个元素为 1 ,foo 中第二个元素为 2,car / cdr 过程不一定获取的是数据对象中的单个元素,也可以是复合的结构。

2.2 - 表 Lists

2.2.1 - 单元素表和空表


我们使用前一小节点对中的 cons 过程,构建一个特殊的点对,它的两个域,一个为 1 ,另一个为 null 也就是空,得到只有一个元素的点对,也是只包含一个元素的表。

(cons 1 null)
; (1)

定义 bar 符号为只有一个元素的点对,对其进行 car, cdr 操作

(define bar (cons 1 null))
bar
; 检测 bar 得到结果 (1)(car bar)
; 1
(cdr bar)
; ()

空的括号 () 是另一种表示 null 的形式,也是一个不包含任何元素的表。也就是说任何一个表最后一个元素都为 null 。

当我们对解释器输入这个特殊的符号 null 时,我们同样得到 空表

null
; ()

2.2.2 - 复合操作

(cons 1 (cons 2 null))
; (1 2)

创建一个包含 2 和 null 的点对,接着创建一个点对元素为 1 和刚刚创建的点对。获得一个点对 (1 2),但解释器表示为包含元素为 1 和 2 的表,也就是说表结构为很多点对的集合。

(cons 1 (cons 2 (cons 3 null)))
; (1 2 3)

使用 (cons 2 (cons 3 null)) 可以获得一个包含 2 和 3 的表,使用结果作为右域与元素 1 创建点对,得到 一个包含元素为 1 2 3 的表。

定义一个符号 mylist 为包含元素 1 2 3 的表

(define mylist (cons 1 (cons 2 (cons 3 null))))mylist
;(1 2 3)(car mylist)
;1(cdr mylist)
;(2 3)

对 mylist 应用 car 得到此表的第一个元素
对 mylist 应用 cdr 则得到所有剩下的元素

(cadr mylist)
; 2

cadr 表示首先进行 cdr ,然后进行 car

(car (cdr mylist))

cdr mylist 得到子表 (sublist) :(2 3)
接着 对此子表应用 car,也就是获取此子表的第一个元素,即 2

同样的

(caddr mylist)
; 结果为 3

cdr mylist 为 (2 3) ,对结果再次 cdr 为 3,car 此结果即为 3

速记:复合的左右域操作,顺序为从右向左。

2.2.3 - list 过程

我们也可以使用前一篇文章中见到的 list 过程来创建表。

(equal? (list 1 2 3) mylist)

过程 list 用于构建表,equal? 用于比较两个元素内容是否相等,比较使用 list 过程构建的表和使用 cons 构建的表是否相同,得到结果

#t

在 Scheme 中布尔值有两个 #t 和 #f , #t 表示 true, #f 表示 false

注意跟 C 语言或其他编程语言不一样的是
if (0)if (#f) 不等价 if (0) 会进入 if 分支,if (#f) 则不会,

(list-ref lst n)

list-ref 是一个用于获取表中第 n 个元素的过程

(list-ref (list "a" "b" "c") 1)
; "b"
(list-ref (list "a" "b" "c") 2)
; "c"

list-ref 过程有两个参数,第一个参数为表,第二个参数为表中的第 n 个元素,与 C 语言相同,计数从 0 开始,当计数为 1 时,获取表中第二个元素,即 "b" , 当计数为 2 时,则获取表中第三个元素,也就是 "c"

III - Loops

如何简略地实现 list-ref 过程?

(define (my-list-ref lst n)(if (zero? n) ; 如果 n 为 0 (car lst) ; 返回 lst 的第一个元素(my-list-ref (cdr lst) (- n 1)))); 否则进行递归操作,获取 lst 除第一个意外子表的第 n-1 个元素 (my-list-ref (list "a" "b" "c") 1)
; "b"
(my-list-ref (list "a" "b" "c") 2)
; "c"

调用实现方式比较粗糙的 my-list-ref 过程,在参数相同时,得到相同的运行结果

此种实现方式被称为 “Loops” ,在其他的编程语言中称为 loop(循环)或 recursion(递归)

IV - 两种特殊的过程

4.1 - Map

(map procedure lst)
map 过程对参数表 lst 中的每一个元素应用过程 procedure 。

; 定义一个符号 baz 内容为包含 1 2 3 三个元素的表
(define baz (list 1 2 3))
; 定义一个过程 double ,结果为入参乘以 2
(define (double x) (* x 2))(map double baz)
; (2 4 6)

对表 (1 2 3) 中的每一个元素应用 double 过程得到结果 (2 4 6)

; 定义一个过程 double-all
(define (double-all x) (map double x))(double-all baz)
; (2 4 6)

这次只需要调用一个过程就可以得到相同的结果。

那么我们如何简略地实现 map 过程呢?

(define (my-map fn lst)(if (null? lst)null(cons (fn (car lst)) (my-map fn (cdr lst)))))(my-map double baz)
; (2 4 6)

my-map 的实现也是通过构建递归,首先如果为空则返回空,

if (null? lst)null

判断是否为空 返回 null ,这里这里不仅是特殊情况处理,也是递归结束条件,如果处理到最后一个元素 (根据本文前面的内容,list 的最后一个元素为 null),则返回 null 结束

不为空 就会创建一个点对,此处应用到了 2.2 节中可以使用 cons 过程创建 list (表) 的内容

(cons (fn (car lst)) (my-map fn (cdr lst)))

生成表第一个元素为对表的第一个元素应用 fn ,(cdr lst) 获取除了第一个元素外,lst 中剩余的所有元素 因此,生成表的第二个元素也会获取原表第二个元素,并对此元素应用 fn ,依次类推。即对表中的所有元素都应用了 fn 。

4.2 - Fold

(define qux (list 1 2 3 4))
; 定义符号 qux 内容为 (1 2 3 4) 的表(foldr + 0 qux)
; 结果为 10

调用 foldr 过程有三个入参, + 0 qux,0 为起始元素,然后将 0 与 qux 中的元素从后向前依次累加,即:

0 + 4
4 + 3
7 + 2
9 + 1

结果为 10

foldr 表示 fold up 堆叠,从最后一个元素开始一个一个叠起来。
有一些类似 C++ 标准库的 std::accumulate 函数,累加 需要指定初始值,因此

; 指定初始值为 2000
(foldr + 2000 qux)
; 结果为 2010

foldr 不仅可以指定累加 还可以指定其他过程,如

(foldr * 1 qux)
; 结果为 24

计算过程为:

1 * 4
4 * 3
12 * 2
24 * 1

结果为 24

同理

(foldr * 0 qux)
; 0

对于 map 同样的操作,我们如何实现 foldr

(define (my-foldr fn start lst)(if (null? lst)start(fn (car lst) (my-foldr fn start (cdr lst)))))(my-foldr + 0 qux)
; 10
(my-foldr * 1 qux)
; 24

首先判断是否为 null 与 my-map 一样,既是特殊情况处理,又是结束条件,返回 start

(fn (car lst) (my-foldr fn start (cdr lst)))

其他情况返回 计算 fn (第一个元素,剩余元素 与 start 元素fn 的结果) 。剩余元素仍然是 lst 则 返回 第二个元素与剩余元素 加 start 元素 fn 的结果…

以此类推,递归到最后一个元素时,则计算 最后一个元素 与 start 元素 fn 的结果。并返回上层调用,计算倒数第二个元素与这个结果的 fn 的值,然后返回更上一层调用…

举例 如果 lst 表中有两个元素 (1 2) , fn 为 +

则递归过程展开

(+ 1 (my-foldr + start (cdr lst)))
; 再展开
(+ 1 (+ 2 start))
; 即 start + 2 + 1

V - 注意事项

mzscheme 称空为 null ,其实是 nil

(define nil null)

【Scheme】Scheme 编程学习 (二) —— 基础相关推荐

  1. python3多线程编程_Python 3多线程编程学习笔记-基础篇

    本文是学习<Python核心编程>的学习笔记,介绍了Python中的全局解释器锁和常用的两个线程模块:thread, threading,并对比他们的优缺点和给出简单的列子. 全局解释器锁 ...

  2. .NET网络编程学习(二)

    System.Net.Sockets有很多类,其中最重要的就是Socket类. Socket类 public class Socket : IDisposable Socket 类为网络通信提供了一套 ...

  3. Python编程学习之基础数据类型

    文章目录 数字类型 整型(int) 浮点数(float) 复数(complex) 布尔型(bool) 字符串(str) 数据类型查看与转换   在程序设计过程中,我们往往会根据用途而使用不同形式的数据 ...

  4. c++面向对象高级编程 学习二 带指针的类

    带指针的类,必须要自己写拷贝构造和赋值构造 拷贝构造:参数和类的类型一样的构造函数 赋值构造:重写操作符=,且其参数和类的类型一样 class String {public: String(const ...

  5. springBoot学习(二) 基础运行原理

    结论:SpringBoot所有的自动配置都是在启动的时候扫描并加载:spring.factories所有的自动配置类都在这里面,但是不一定生效,要判断条件是否成立,只要导入了对应的start,就有对应 ...

  6. 编程需要那些数学和计算机知识点,学习编程需要哪些基础?

    原标题:学习编程需要哪些基础? 随着互联网飞速发展,很多互联网人才需求越来越大,不论是大学生还是就业人士.不论是科班还是非科班,相继涌入互联网行业的大军中.很多非科班或学历不高的朋友通过计算机培训成为 ...

  7. java并发编程学习一

    java并发编程学习一 什么是进程和线程? 进程是操作系统进行资源分配的最小单位 进程跟进程之间的资源是隔离的,同一个进程之中的线程可以共享进程的资源. 线程是进程的一个实体,是CPU 调度和分派的基 ...

  8. 【干货】程序员必备的中文在线编程学习网站!

    迫于英语烂得一塌糊涂,本人愤而转向中文编程学习网站,给大伙推荐几个我认为质量和性价比都很高的网站,放心食用! 在线OJ及部分题解 先推一波OJ(在线编程评测平台).我的人生信条是:没有什么比亲自动手c ...

  9. 【Scheme】Scheme 编程学习(一) —— 概述

    Scheme 编程学习(一) -- 概述 文章目录 Scheme 编程学习(一) -- 概述 概述 I - 语法简洁 1.1 - 算数运算 (arithmetic) 1.2 - 定义值 1.3 - 定 ...

最新文章

  1. gc方法写法_清标的内容、技巧及书写方式
  2. 《Effective C#》Part I:第一部分总结
  3. ITK:将网格转换为非结构化网格
  4. Linux Shell脚本多循环语句练习题
  5. linux 测试cpu计算圆周率_Linux下测试CPU性能
  6. 线性表—顺序存储结构-顺序表
  7. CSS中常见的6种文本样式
  8. DDD(Domain-Driven Design)领域驱动设计-(一)整体概述
  9. HAUT校赛--某科学的打麻将
  10. 最佳网络工具--OpManager局域网管理软件
  11. VS2017使用Qt教程
  12. i710870h和i710875h有多大差距?哪个好?
  13. SAP BW顾问如何保持市场竞争力?【转自WKingChen的博客】
  14. SRVCC关键场景及Log分析
  15. 2021年山东省安全员C证试题及解析及山东省安全员C证模拟考试
  16. Codeforces 1635 E. Cars 二分图+拓扑排序
  17. 【Markdown语法】字体颜色大小及文字底色设置
  18. python ccf题解 201412-3 集合竞价
  19. 两台计算机之间的直连
  20. ORB-SLAM2 --- KeyFrame::AddConnection函数

热门文章

  1. erwin连接oracle报错,ERWin如何连接数据库
  2. Python爬虫框架 scrapy 入门经典project 爬取校花网资源、批量下载图片
  3. 排名提升29位!真我realme再登谷歌X凯度BrandZ中国全球化品牌50强
  4. 从零开始学数据分析之——《线性代数》第一章 行列式
  5. 511遇见易语言大漠多线程自动切换账号循环登录任务模板
  6. Tribonnbsp;M3自定义工具栏出错处理经…
  7. 主成分分析和因子分析的介绍、区别和联系
  8. ubuntu中apt和apt-get
  9. 什么是FPGA,PAL,EPLD?
  10. oracle在w10中无法安装软件下载,win10系统下载软件被阻止安装该怎么办?