作业 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)!
我们来提交一份作业。这需要以下几步:
- 为作业建一个文件夹(可选,但强烈推荐,原因我们马上会看到)
- 在那个文件夹里完成作业(如果作业已经完成,就把文件移过去)
- 运行
submit命令 - 检查作业是否提交成功
我们要提交一份名为 “units” 的作业,它会告诉教职人员你要做多少个单元。
创建文件夹
在终端中输入:
mkdir units
这会告诉计算机创建一个名为 units 的目录(文件夹)。你可以运行 ls 来确认它确实存在(顺便看看当前目录里还有什么)。
现在我们需要进入那个文件夹,所以我们要执行:
cd units
完成作业
要完成这份作业,你必须创建一个名为 units 的文件(放在名为 units 的目录里)。在这个文件中,写下你计划做哪些单元。例如,如果你要做单元 0、1、2 和 3,就写:
0 1 2 3
请不要加入任何多余的空格或空行!
提交
创建好文件后,你可以这样提交作业:
submit units
这是在告诉计算机:你要提交名为 “units” 的作业。按照屏幕上出现的指示操作即可。
检查提交情况
下面的命令可以查看你的提交时间:
glookup -t
今天就到这里。你可能有兴趣从家里连接来做这些工作。详情见顶部的 Resources 链接!