我有一个问题我不明白
let
如何在cond
中工作,用if
我理解它但不是用cond
...
这是我的带有
let
的代码:
(define add2
(lambda (l)
(cond ((null? l) l)
(let ((R (add2 (cdr l))))
((list? (car l)) (cons (add2 (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R))))))
当我在我的清单上尝试时,它不起作用。
通常当我给出我的清单时:
(add2 '(2 b (10 a (56 3) 5) 4))
它应该给我这个:
(4 b (12 a (58 5) 7) 6))
它不...它说:
let: bad syntax
我想可能是这个,但我检查了每个括号并没有发现遗漏的东西......
但是当我删除我的
let
并尝试不使用它时,它有效!
(define add2
(lambda (l)
(cond ((null? l) l)
((list? (car l)) (cons (add2 (car l)) (add2 (cdr l))))
((number? (car l)) (cons (+ 2 (car l)) (add2 (cdr l))))
(else (cons (car l) (add2 (cdr l)))))))
(add2 '(2 b (10 a (56 3) 5) 4))
进入(4 b (12 a (58 5) 7) 6))
因此我不明白为什么它不起作用,我将不胜感激任何帮助!
A
cond
具有以下结构:
(cond
[predicate consequent1 ... consequent-tail]
...
[else alternative1 ... alternative-tail])
你的代码被自动解释为:
(cond
[(null? l) l]
[let ; check the variable let if it's not #f
((R (add2 (cdr l)))) ; call the procedure R and the call the procedure R should return
((list? (car l))(cons (add2 (car l)) R)) ; call list? and then call the procedure it should return
((number? (car l))(cons (+ 2 (car l))R)) ; call number? and then call the procedure it should return
(else (cons (car l) R)]
))))
现在我明白你在追求什么了。很久以前我制作了这个宏,它在
cond
: 中添加了对绑定的支持
(define-syntax defcond
(syntax-rules (else bind define =>)
((_ "build" terms ())
terms)
((_ "build" alternative ((bind (b e) ...) . rest))
(defcond "build" (let ((b e) ...) alternative) rest))
((_ "build" alternative ((bind name (b e) ...) . rest))
(defcond "build" (let name ((b e) ...) alternative) rest))
((_ "build" alternative ((define b e) . rest))
(defcond "build" (letrec ((b e)) alternative) rest))
((_ "build" alternative ((predicate consequent) . rest))
(defcond "build" (if predicate consequent alternative) rest))
((_ "build" alternative ((predicate consequent => (b e) ...) . rest))
(defcond "build" (if predicate consequent (let ((b e) ...) alternative)) rest))
((_ "build" alternative ((predicate consequent) . rest))
(defcond "build" (if predicate consequent alternative) rest))
((_ "maybe-else" ((else expression) . rest))
(defcond "build" expression rest))
((_ "maybe-else" ((something expression) . rest))
(defcond "build" #f ((something expression) . rest)))
((_ "reverse" terms ())
(defcond "maybe-else" terms))
((_ "reverse" (fterms ...) (term1 terms ...))
(defcond "reverse" (term1 fterms ...) (terms ...)))
((_ terms ...)
(defcond "reverse" () (terms ...)))))
使用它我可以像这样编写您的代码:
(define (add2 l)
(defcond
[(null? l) l]
[bind (a (car l)) (d (cdr l))]
[(list? a) (cons (add2 a) d)]
[(number? a) (cons (+ 2 a) d)]
[else (cons a d)]))
还支持
letrec
/define
和命名let
的结构类型:
(define (reverse lst)
(defcond
[bind loop (lst lst) (acc '())]
[(null? lst) acc]
[else (loop (cdr lst) (cons (car lst) acc))]))
我不完全确定这是否是在条件中表达绑定的最佳方式,所以自从我在 2017 年编写宏以来我就没有碰过这个,从那以后它就一直在我的垃圾文件夹中 :-p.
(define add2
(lambda (l)
(cond ((null? l) l)
(let ((R (add2 (cdr l))))
((list? (car l)) (cons (add2 (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R))))))
你不能制定自己的语法 - 但你必须遵循
cond
语法
其中说:
(cond ((condition-1 consequent-1)
(condition-2 consequent-2)
...
(else final-consequent)))
所以没有地方放
let
,你可以把它放进去。
cond
s环绕内部cond
一个let
而不是编写允许它的宏 - 这很复杂 - 我建议你只遵循现有的语法并嵌套两个
cond
s.
你的
let
表达式应该放在结果中。
(define add2
(lambda (l)
(cond ((null? l) l)
(else (let ((R (add2 (cdr l))))
(cond ((list? (car l)) (cons (add2 (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R))))))))
if
和cond
包裹let
内部cond
但是我们看到外面的
cond
只是测试一个条件(null? l)
所以它可能是一个普通的 if
- 这样可以节省一些打字时间:
(define add2
(lambda (l)
(if (null? l)
l
(let ((R (add2 (cdr l))))
(cond ((list? (car l)) (cons (add2 (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R)))))))
你可以在球拍中使用更短的函数定义形式:
(define (add2 l)
(if (null? l)
l
(let ((R (add2 (cdr l))))
(cond ((list? (car l)) (cons (add2 (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R))))))
所以现在我明白你真正想要的是什么了。您只想在嵌套列表 2 中添加数字元素。 这种传统上处理嵌套列表的递归函数 最后有一个
*
。
让这个函数是尾递归的:
(define (add2* l (acc '()))
(cond ((null? l) (reverse acc))
((list? (car l)) (cons (add2* (car l)) (add2* (cdr l))))
((number? (car l)) (cons (+ 2 (car l)) (add2* (cdr l))))
(else (cons (car l) (add2* (cdr l))))))
好吧,现在我明白了,您想节省打字工作...
(define (add2* l (acc '()))
(cond ((null? l) (reverse acc))
(else (let ((R (add2* (cdr l))))
(cond ((list? (car l)) (cons (add2* (car l)) R))
((number? (car l)) (cons (+ 2 (car l)) R))
(else (cons (car l) R)))))))
map-tree
这东西实际上是一棵地图树:
(define (map-tree func tree (acc '()))
(cond ((null? tree) (reverse acc))
((list? (car tree)) (cons (map-tree func (car tree)) (map-tree func (cdr tree))))
(else (cons (func (car tree)) (map-tree func (cdr tree))))))
使用这个更通用的函数,您可以通过以下方式定义您的
add2*
:
(define (add2 x)
(if (number? x)
(+ 2 x)
x))
(define (add2* tree)
(map-tree add2 tree))
并测试它:
(add2* '(2 b (10 a (56 3) 5) 4))
;; => '(4 b (12 a (58 5) 7) 6)
map-tree
的泛化使您可以定义
其他类型的类似功能 - 因为它解耦了
应用于树的每个元素的实际函数
来自函数在树上的遍历和应用。
例如你可以轻松定义一个
add5*
:
(define (add5 x)
(if (number? x)
(+ 5 x)
x))
(define (add5* tree)
(map-tree add5 tree))
addN
和addN*
因为这也遵循一些模式,你可以让一个函数 返回相应的
add7
和add7*
:
(define (generate-addN n)
(lambda (x)
(if (number? x)
(+ n x)
x)))
(define (generate-addN* n)
(lambda (tree)
(map-tree (generate-addN n) tree)))
这些功能为您生成
addN
和addN*
的功能:
(define add7 (generate-addN 7))
(define add7* (generate-addN* 7))
addN*
函数或者你直接只是一个广义的
addN*
函数,它需要
n
和 tree
:
(define (addN* n tree)
(map-tree (generate-addN n) tree))
或者将
generate-addN
写成 lambda 表达式:
(define (addN* n tree)
(map-tree (lambda (x)
(if (number? x)
(+ n x)
x))
tree))
并使用它
(addN* 7 '(2 b (10 a (56 3) 5) 4))
;; => '(9 b (17 a (63 10) 12) 11)
另一种将列表元素绑定到变量并根据其类型执行代码的更高级方法是使用模式匹配。
以下适用于 Racket(可能需要
(require racket/match)
,具体取决于您的 #lang
)、Guile(带有 (use-modules (ice-9 match))
)、Chicken(带有 matchable
egg),可能还有任何其他支持 Wright 的方案-样式模式匹配.
(define (add2 l)
(match l
('() '()) ; Empty list
(`(,(? list? a) . ,rest) ; List where the car is a list?
(cons (add2 a) (add2 rest)))
(`(,(? number? a) . ,rest) ; List where the car is a number?
(cons (+ a 2) (add2 rest)))
(`(,a . ,rest) ; List where the car is some other type
(cons a (add2 rest)))))
> (add2 '(2 b (10 a (56 3) 5) 4))
'(4 b (12 a (58 5) 7) 6)