如何构造复制仅在运行时在Racket中已知的字段?

时间:2014-10-09 11:15:28

标签: scheme lisp racket

在Racket中,可以更改特定字段的结构副本。以下内容:

(struct foo (a b c))
(define tst (foo 1 2 3))
(struct-copy foo tst [a 4])

应该产生(foo 4 2 3)

我想知道,如果我想修改的字段在编译时不知道怎么办?比如说我想编写一个可以根据用户输入修改a,b或c的函数。如果我有一个功能:

(define (update-foo somefoo param)
  (struct-copy foo somefoo [param 4]))

然后我收到错误struct-copy: accessor name not associated with the given structure type。因为它正在治疗' param'作为访问者,而不是评估它并将符号/字符串作为访问者处理。

所以我想知道,是否可以使用struct-copy,只在运行时知道目标字段名称?如果没有,是否有某种解决方法,或者我应该咬紧牙关并将foo更改为可变结构(如set-foo-a!等在运行时存在)?

2 个答案:

答案 0 :(得分:2)

你可以使用句法扩展来做到这一点:

(define-syntax-rule (update-foo somefoo param)
  (struct-copy foo somefoo [param 4]))

测试:

> tst
(foo 1 2 3)
> (update-foo tst b)
(foo 1 4 3)

Racket中的宏步进器显示以下转换:

(module anonymous-module racket
  (#%module-begin
   (struct foo (a b c) #:transparent)
   (define tst (foo 1 2 3))
   (define-syntax-rule (update-foo somefoo param) (struct-copy foo somefoo [param 4]))
   (update-foo tst b)))

(module anonymous-module racket
  (#%module-begin
   (struct foo (a b c) #:transparent)
   (define tst (foo1 1 2 3))
   (define-syntax-rule (update-foo somefoo param) (struct-copy foo somefoo [param 4]))
   (struct-copy foo tst [b 4])))

答案 1 :(得分:2)

(这最初是评论,但OP要求我将其作为答案发布)

如果你想拥有任意的运行时字段名称,那么听起来好像你在键入一个字典而不是一个结构...在这种情况下你应该使用一个字典。

Racket struct的一个特征是引用字段的速度可以更快,因为它是编译时已知的静态偏移量。另一个特点是您无法在编译时添加未知字段,或者省略字段。

当这些特征具有优势时(即,当您不想意外添加或省略字段时),您应该使用结构。否则(即当你想要故意添加或省略字段时 - 这听起来像你的情况)你应该改为使用某种字典,例如哈希表或关联列表。