内容提要
本文介绍了Racket中的条件表达式、递归和复合数据。Racket的代码风格包括标识符的大小写敏感、使用连字符而不是下划线、参数放在同一行或同一列等。Racket中的条件表达式使用if和cond函数,可以比较数字和字符串,还有一些特殊的条件表达式函数。递归在Racket中用于循环,可以计算斐波那契数列和阶乘等。复合数据可以使用cons函数创建,可以使用car和cdr函数获取元素,还可以使用quasiquote和unquote实现动态构建列表。字符串在Racket中也是复合数据,可以使用substring和string-append函数操作。树可以使用列表或struct表示。
延伸解读
Racket 代码风格:不仅仅是美观
文章强调 Racket 标识符区分大小写但少用大写,偏好连字符而非下划线,参数对齐或同行,右括号集中放置。这些约定并非随意,而是为了提升代码可读性,尤其在嵌套结构多的 Lisp 方言中。DrRacket 的自动缩进和括号高亮功能进一步辅助遵守这些风格。遵循统一风格能让代码更易维护,也便于社区交流。
条件表达式:if 与 cond 的选用
Racket 的 if 必须包含真假两个分支,且通常不嵌套,因为 cond 更通用易读。cond 使用方括号组织问题-答案对,按顺序测试,遇到第一个真值即返回对应答案。and 和 or 具有短路特性,可返回非布尔值。理解这些差异有助于写出简洁的条件逻辑,避免深层嵌套。
递归与尾递归:空间效率的权衡
Racket 用递归实现循环,如斐波那契和阶乘。普通递归在计算后还需额外操作,空间消耗与递归深度成正比。尾递归将递归调用置于末尾,可避免空间增长,但并非所有函数都能改写为尾递归,例如斐波那契数列。文章展示了阶乘的尾递归版本,并指出辅助函数命名惯例(-helper)。
复合数据:从 cons 到树
cons 构造点对,car 和 cdr 提取元素,列表是嵌套 cons 的简写。quote 和 quasiquote 提供了字面量和动态构建列表的方式。字符串本质是字符列表,可用 substring 和 string-append 操作。树可用嵌套列表或 struct 表示,struct 能提升可读性。递归可自然应用于列表处理,如求和与映射。
Q&A
Racket 中的条件表达式是如何工作的?
Racket 中的条件表达式使用 if 和 cond 函数,if 表达式包含条件、为真时的表达式和为假时的表达式,cond 表达式则包含一系列问题-答案对。
如何在 Racket 中实现递归?
在 Racket 中,递归通过函数内部调用自身来实现,通常结合条件检查来终止递归,例如计算斐波那契数列和阶乘。
Racket 中的复合数据是如何创建的?
复合数据可以使用 cons 函数创建,cons 函数接受两个参数并将其构造成一个复合数据结构。
Racket 中的字符串如何操作?
在 Racket 中,可以使用 substring 函数获取子串,使用 string-append 函数连接字符串,还可以将字符串转换为字符列表进行操作。
Racket 中的 if 表达式与其他语言的 if 语句有什么不同?
Racket 的 if 表达式有值,第二和第三个子表达式必须存在,且通常不嵌套,而是使用更易读的 cond 表达式。
如何在 Racket 中使用 cond 表达式?
cond 表达式包含一系列问题-答案对,Racket 会逐个检查问题,直到找到值为 #t 的问题并执行对应的答案表达式。