Racket 重载结构构造函数?

Racket 重载结构构造函数?,racket,Racket,我的问题和被问的问题一样,但给出的答案实际上不起作用 我有一组从父结构a继承的结构,它有两个字段,我想让所有子结构都成为可选的。以前我使用的是#:auto,但事实证明这并不是我想要的,因为它破坏了结构复制之类的方法,而且我确实希望能够在创建结构时选择性地为这些字段提供值 我还发现了一些关于结构的可选参数的其他问题,但答案都建议定义一个自定义构造函数并使用它。不幸的是,我已经有很多使用常规构造函数的代码,所以我真正想要的是这个自定义构造函数与结构本身具有相同的名称。我链接的问题的答案是我想要的,但

我的问题和被问的问题一样,但给出的答案实际上不起作用

我有一组从父结构
a
继承的结构,它有两个字段,我想让所有子结构都成为可选的。以前我使用的是
#:auto
,但事实证明这并不是我想要的,因为它破坏了
结构复制
之类的方法,而且我确实希望能够在创建结构时选择性地为这些字段提供值

我还发现了一些关于结构的可选参数的其他问题,但答案都建议定义一个自定义构造函数并使用它。不幸的是,我已经有很多使用常规构造函数的代码,所以我真正想要的是这个自定义构造函数与结构本身具有相同的名称。我链接的问题的答案是我想要的,但不幸的是,它只在REPL中有效,因为允许有重复的定义。在REPL之外,我得到了一个错误,比如:exn:my app中标识符的
模块:重复定义(当运行链接问题的答案时)

编辑:我知道重复定义的问题是因为结构id也绑定到转换器。我不想阻止这种定义的发生;我想要一个绑定到该结构的构造函数和转换器的名称,其中构造函数不是默认的


有没有一种方法可以很好地处理现有代码?

结构将用结构的名称定义两个实体。包含结构信息的构造函数和转换器绑定

为了避免“重复标识符”错误,您可以使用
#:省略define syntax

另一种方法是在子模块中定义结构,并仅导出所需的内容(并可能重命名某些标识符)

输出:

(horse "black")
(horse "red")
(horse "black")
(horse "red")
"blue"
编辑

在匹配扩展器的帮助下,可以使用匹配解决方案。 注意:由于使用了
:extra name
,您至少需要6.5版才能正常工作

#lang racket

(module horse racket
  (provide (struct-out Horse)
           make-horse)
  (struct horse (color)
    #:extra-name Horse
    #:extra-constructor-name make-horse
    #:transparent))

(require 'horse)

; the custom horse constructor
(define (my-make-horse #:color [color "black"])
  (make-horse color))

(define-match-expander horse
  ; match expander
  (λ (pat)
    (syntax-case pat ()
      [(_horse more ...)
       #'(Horse more ...)]))
  ; constructor
  (λ (stx)
    (syntax-case stx ()
      [(_horse arg ...)
       (syntax/loc stx
         (my-make-horse arg ...))])))

(horse)
(horse #:color "red")

(match (horse #:color "blue")
  [(horse color) color])
输出:

(horse "black")
(horse "red")
(horse "black")
(horse "red")
"blue"

进一步研究前面提到的新结构关键字,我想我已经找到了一个更简洁的解决方案,更重要的是,它更容易抽象为宏(那些模块和需求让我非常困难)。我想我会分享它以备将来参考。同样,这需要一个夜间球拍构建。我用的是6.5.0.7

(注意:这里使用
case lambda
来定义关键字参数只是我的首选。)

示例用法:

> (define black-beauty (horse))
> black-beauty
(horse "black")

> (define ginger (horse "red"))
> ginger
(horse "red")

> (match black-beauty
    [(horse color) color])
"black"

> (match ginger
    [(horse color) color])
"red"

> (horse-color black-beauty)
"black"

> (horse-color ginger)
"red"

简言之:实例化、匹配和访问字段的工作似乎与您刚刚使用
struct
时所期望的一样。结构id也可以用作标识符,而不存在任何语法问题。我真的不认为该部分有多大的实际用途,但我认为它很好。

这可以重载构造函数,但现在我遇到了一个问题,因为我还需要将转换器绑定到相同的名称以进行匹配。因此,我希望能够将重载构造函数和转换器绑定到同一个名称。谢谢,这看起来很有希望!奇怪的是,我在#:额外的名字上遇到了麻烦,尽管我的球拍是6.5。我至少会记住这一点,以便在某个时候解决问题。从#:extra name上的文档中,看起来(struct out Horse)将导出Horse color而不是Horse color,因为Horse只是绑定到struct信息。对吗?你可能需要一个夜间构建。看,谢谢!它适用于6.5.0.7。为了回答我自己在评论后编辑的问题,struct out导出的是马的颜色,而不是马的颜色。看起来我还可以实际使用Horse作为构造函数,所以不需要使用#:额外的构造函数名称,然后导出该标识符。这是一个更好的解决方案!只是为了使这个解决方案更好一点,由
语法/transformer
中的函数处理
(语法id规则()[(\uargs…(f arg…)[\uf])
模式。您可以像
一样使用它(使变量像transformer#“make-horse”)
。这也避免了
设置语法id规则
表单存在的代码>错误。