我正在学习计划,并达到了我目前所学知识的极限。我怀疑宏可能是完成这项工作的正确工具,但是...
我想编写一个过程,其中基于用户提供的表达式来操作关联列表的内容。如果我们有此关联列表,
(define a '((x (1 2 3)) (y (4 5 6)) (z (7 8 9))))
然后,我希望有一个基于关联列表的当前元素将新元素添加到关联列表的过程。
(define (add-element alist proc)
;; this is part that I'm struggling with
)
这里有几个用法示例:
(add-element a '(w (* x y z)))
(add-element a '(w (- (+ y z) (/ y 2)))
我想将这些输入转换为以下内容(对于第二个示例):
(cons
(list 'w
(map (lambda (y z)
(- (+ y z) (/ y 2)))
(cadr (assoc 'y a))
(cadr (assoc 'z a))))
a)
此问题的某些部分似乎可以解决。例如,用户定义的proc的结构使得(car proc)
提供新关联列表元素的键,而(cadr proc)
提供lambda
主体。我编写了一个过程(此处未显示)以展平(car proc)
,提取在关联列表的键中找到的符号并删除重复项。然后,我可以使用该符号列表映射到关联列表,并从关联列表中获取相关元素的列表,以便可以将apply map
模式与lambda
函数一起使用。但是我不知道如何将lambda
函数与符号列表组合在一起。或如何在(cadr proc)
主体中使用lambda
。
编辑:添加代码以显示我使用eval
的失败尝试。
;; https://stackoverflow.com/questions/8382296/scheme-remove-duplicated-numbers-from-list
(define (remove-duplicates ls)
(cond [(null? ls)
'()]
[(member (car ls) (cdr ls))
(remove-duplicates (cdr ls))]
[else
(cons (car ls) (remove-duplicates (cdr ls)))]))
;; https://stackoverflow.com/questions/28753729/how-to-manually-flatten-a-list-in-racket-scheme
(define (flatten obj)
(cond [(null? obj) '()]
[(list? obj)
(append (flatten (car obj))
(flatten (cdr obj)))]
[else (list obj)]))
(define (alist-contains? alist symbol)
(if (member symbol (map car alist)) #t #f))
(define (extract-alist-keys alist expr)
(remove-duplicates
(filter
(lambda (x)
(and (symbol? x) (alist-contains? alist x)))
(flatten expr))))
(define (add-element alist proc)
(define new-key (car proc))
(define body (cadr proc))
(define key-list (extract-alist-keys alist body))
(define values-list (map (lambda (x) (cadr (assoc x alist))) key-list))
(define new-values (eval '(apply map (lambda ,key-list body) ,values-list)))
(cons (list new-key new-values) alist))
(add-element a '(w (- (+ y z) (/ y 2))))
我使用eval
拼凑了一个解决方案。这是带有add-element
和quasiquote
的有效应用程序的unquote-splicing
过程(我还将所有define
语句都更改为let*
块):
(define (add-element alist proc)
(let* ([new-key (car proc)]
[body (cadr proc)]
[key-list (extract-alist-keys alist body)]
[values-list (map (lambda (x) (cadr (assoc x alist))) key-list)]
[new-values (eval `(apply map (lambda (,@key-list) (,@body)) values-list))])
(cons (list new-key new-values) alist)))
[如果有更多经验的人有更好的答案,我将等待几天,然后接受此答案。