作业 1

CS61AS 第一次作业:包含 8 道递归与列表处理练习,以及模板获取、自动评分器和作业提交的完整说明。

模板

在终端中输入下面的命令,把模板文件复制到当前目录(注意末尾有一个句点):

cp ~cs61as/autograder/templates/hw1.rkt .

或者,你可以在这里下载模板。

提示

如果做作业时卡住了,复习一下第 0.3 课,那里有对递归的详细讲解。

自动评分器

如果你在实验室的计算机上做作业,grader 命令会运行自动评分器。如果你在自己的个人电脑上做,需要下载 grader.rkt 和 HW 1 测试文件。

练习 1

写一个过程 dupls-removed,给定一个句子作为输入,返回删去重复单词后的句子。这道题用到了递归。

;; 应输出 (c a d e b)
(dupls-removed '(a b c a e d e b))

;; 应输出 (a b c)
(dupls-removed '(a b c)) ;;

;; 应输出 (b a)
(dupls-removed '(a a a a b a a))

提醒一下,在实验室计算机上可以这样运行自动评分器:

grader hw1 hw1.rkt dupls-removed

在自己的机器上:

racket -tm grader.rkt -- hw1-tests.rkt hw1.rkt dupls-removed

练习 2

写一个过程 count-word,接受一个句子和一个单词作为实参,输出该单词在句子中出现的次数。

;; 应输出 2
(count-word '(i really really like 61as) 'really)

;; 应输出 0
(count-word '(i lambda racket) 'love)

练习 3

解释一下:如果在 pigl 过程中用 new-if(来自实验 0)代替 if,会发生什么?

下面是之前实验中的 pigl 定义:

(define (pigl wd)
  (if (pl-done? wd)
      (word wd 'ay)
      (pigl (word (bf wd) (first wd)))))

(define (pl-done? wd)
  (vowel? (first wd)))

(define (vowel? letter)
  (member? letter '(a e i o u)))

练习 4

写一个过程 squares,接受一个由数字组成的句子作为实参,返回这些数字的平方组成的句子。

;; 应输出 (1 4 9)
(squares '(1 2 3))

练习 5

写一个过程 switch,接受一个句子作为实参,返回一个新句子:其中每一处 I 或 me 都替换为 you,每一处 you 都替换为 me——但句首的 you 例外,它要替换为 I。(I 是唯一应该大写的单词。)

;; 应输出 (I told you that you should wake me up)
(switch '(you told me that I should wake you up))

提示

可以考虑写一个辅助函数,只处理问题的一般情况——也就是说,辅助函数不用管”句首要除外”这部分。然后用这个辅助函数来写 switch,并在 switch 的过程体中处理特殊情形。

练习 6

写一个谓词 ordered?,接受一个由数字组成的句子作为实参,如果数字按升序排列就返回 #t,否则返回 #f。

(ordered? '(1 2 3)) ; #t
(ordered? '(2 1 3)) ; #f
(ordered? '(2)) ; #t

练习 7

写一个过程 ends-e,接受一个句子作为实参,返回只包含以字母 E 结尾的单词的句子。

;; 应输出 (please the above the blue)
(ends-e '(please put the salami above the blue elephant))

练习 8

大多数 Lisp 版本都提供像我们见过的那样的 and 和 or 过程。原则上,它们没有理由不能是普通过程,但某些 Lisp 版本把它们做成了特殊形式。

例如,假设我们求值 (or (= x 0) (= y 0) (= z 0))。如果 or 是普通过程,那么在调用 or 之前,三个实参表达式会全部被求值。但是,如果变量 x 的值是 0,我们就知道无论 y 和 z 取什么值,整个表达式都为真。在把 or 实现为特殊形式的 Lisp 解释器中,可以逐个求值实参,直到找到一个为真的实参或者实参用完为止。

设计一个测试,判断 Racket 的 and 和 or 是特殊形式还是普通函数。这个问题有点棘手,但它会让你更深入地思考求值过程。解释器把 or 当作特殊形式、逐个求值实参,这样做有什么好处?你能想到把 or 当作普通过程的好处吗?

提交作业

重要

如果提交时遇到麻烦,请在 Piazza 上提问或联系助教。

警告

提交前: 确保你的文件能在 Racket 中加载。你可以在 Racket 中输入 (enter! "hw1.rkt") 来验证,其中 “hw1.rkt” 是你的作业文件名。无法在 Racket 中加载的作业不会获得分数。

要提交作业,你需要登录到任意一台实验室计算机。如果你想从家里提交,必须远程连接到实验室计算机。后面会详细介绍。

现在,点击左侧的 “Terminal” 图标。Terminal 是一个终端模拟器,一种通过文本命令直接与计算机交互的方式。它有点像你整台计算机的”解释器”。你可以用 xterm 做很多有用的事,比如浏览和操作文件系统(想想 Windows 资源管理器)、提交作业(就像我们现在做的),以及启动 Racket 解释器(通过 racket)!

我们来提交一份作业。这需要以下几步:

  1. 为作业建一个文件夹(可选,但强烈推荐,原因我们马上会看到)
  2. 在那个文件夹里完成作业(如果作业已经完成,就把文件移过去)
  3. 运行 submit 命令
  4. 检查作业是否提交成功

我们要提交一份名为 “units” 的作业,它会告诉教职人员你要做多少个单元。

创建文件夹

在终端中输入:

mkdir units

这会告诉计算机创建一个名为 units 的目录(文件夹)。你可以运行 ls 来确认它确实存在(顺便看看当前目录里还有什么)。

现在我们需要进入那个文件夹,所以我们要执行:

cd units

完成作业

要完成这份作业,你必须创建一个名为 units 的文件(放在名为 units 的目录里)。在这个文件中,写下你计划做哪些单元。例如,如果你要做单元 0、1、2 和 3,就写:

0 1 2 3

请不要加入任何多余的空格或空行!

提交

创建好文件后,你可以这样提交作业:

submit units

这是在告诉计算机:你要提交名为 “units” 的作业。按照屏幕上出现的指示操作即可。

检查提交情况

下面的命令可以查看你的提交时间:

glookup -t

今天就到这里。你可能有兴趣从家里连接来做这些工作。详情见顶部的 Resources 链接!