【问题标题】:Using dot notation in Racket class functions在 Racket 类函数中使用点表示法
【发布时间】:2016-08-30 10:20:53
【问题描述】:

我有以下课程可以正常工作:

(define myob%
  (class object%
    (super-new)
    (init-field val)
    (define/public (getval) val)
    (define/public (setval v) (set! val v))   ))

(define ob1 (make-object myob% 5))

(send ob1 getval)
(send ob1 setval 10)
(send ob1 getval)

输出:

5
10

下面的正则表达式也很好用:

(define sl (regexp-match #px"^(.+)[.]([^.]+)$" "ob1.getval"))
sl

输出:

'("ob1.getval" "ob1" "getval")

我正在尝试制作一个 fn foo,它应该像“发送”一样工作,但以 (foo ob1.getval)(foo ob1.setval 10) 的形式接受参数。以下宏不起作用:

(define-syntax foo
    (syntax-rules ()
      ((_ sstr ...)
       (define sl (regexp-match #px"^(.+)[.]([^.]+)$"
                                (symbol->string sstr)))
       (send (string->symbol(list-ref sl 1))
             (string->symbol(list-ref sl 2))
             ...))))

(foo ob1.getval)

错误是:

syntax-rules: bad syntax in: (syntax-rules () ((_ sstr ...) (define sl (regexp-match #px"^(.+)[.]([^.]+)$" (symbol->string sstr))) (send (list-ref sl 1) (list-ref sl 2) ...)))

错误在哪里,如何纠正?

【问题讨论】:

  • AFAIK,sstr 表示语法对象,而不是符号,需要用syntax->datum 转换。 (send 的问题正好相反。)
  • 你能用正确的代码把它作为答案吗?
  • 不幸的是,解决这些问题还不够,我不确定正确的代码是什么。

标签: macros scheme racket


【解决方案1】:

要像这样使用点表示法,您需要定义一种新的#lang 语言,并带有它自己的阅读器。有几个工具可以帮助解决这个问题,我将使用其中之一 syntax/module-reader 来定义 #lang send-dot,一旦定义,就可以像这样使用:

#lang send-dot

(define o
  (new (class object% (super-new)
         (define/public (f x) x))))

(o.f "hellooo")

在 Racket 的latest snapshot version 中,可以使用read-cdot 选项。确保您使用的是最新的快照版本,因为在 6.6 中,它已完全损坏。

定义#lang 的一种方法是声明reader 子模块。创建一个名为send-dot 的目录,并添加一个名为main.rkt 的文件。该文件应提供来自球拍的所有内容。

#lang racket

(provide (all-from-out racket))

这还没有定义#lang。但是要尝试一下,您可以转到 DrRacket 的文件菜单,单击包管理器,然后在包源字段中,输入send-dot 目录的路径。一旦你这样做了,你应该可以在另一个文件中使用#lang s-exp send-dot,就像你使用#lang racket一样。

要定义该语言的阅读器并使其成为真正的#lang 语言,您可以添加一个使用syntax/module-reader 作为其语言的reader 子模块。

#lang racket

(provide (all-from-out racket))

;; This submodule defines the reader for the language
(module reader syntax/module-reader
  send-dot)

现在您应该可以像使用#lang racket 一样使用#lang send-dot

现在您还需要做两件事。一、打开read-cdot选项,使(o.method args ...)转换为((#%dot o method) args ...),二、定义#%dot宏,使((#%dot o method) args ...)等价于(send o method args ...)

首先,您可以使用#:wrapper1 选项,使用parameterize 打开read-cdot

#lang racket

(provide (all-from-out racket))

;; This submodule defines the reader for the language
(module reader syntax/module-reader
  send-dot
  #:wrapper1 (lambda (thunk)
               ;; turns on the read-cdot option,
               ;; which will turn o.method into (#%dot o method),
               ;; and (o.method args ...) into ((#%dot o method) args ...)
               (parameterize ([read-cdot #true])
                 (thunk))))

第二件事,你需要定义一个#%dot 宏。 o.method,或者(#%dot o method),需要是调用方法的函数,所以可以使用(lambda args (send/apply o method args))

#lang racket

(provide #%dot (all-from-out racket))

;; transforms (#%dot o method) into a function that calls the method
;; so that ((#%dot o method) args ...) will be roughly equivalent to
;; (send o method args ...)
(define-syntax-rule (#%dot obj-expr method-id)
  (let ([obj obj-expr])
    (lambda args (send/apply obj method-id args))))

;; This submodule defines the reader for the language
(module reader syntax/module-reader
  send-dot
  #:wrapper1 (lambda (thunk)
               ;; turns on the read-cdot option,
               ;; which will turn o.method into (#%dot o method),
               ;; and (o.method args ...) into ((#%dot o method) args ...)
               (parameterize ([read-cdot #true])
                 (thunk))))

现在你应该可以像这样使用#lang send-dot了:

#lang send-dot

(define o
  (new (class object% (super-new)
         (define/public (f x) x))))

(o.f "hellooo")

【讨论】:

  • 太棒了。您能否在这里简单地补充一下,在这种新语言中如何也可以将点用于结构元素(参考stackoverflow.com/questions/39145000/…
  • 对象更容易,因为它们可以依赖动态调度。如果你想要mydog.name,结构会有点困难,但如果你想要将mydog.dog-name 翻译成(dog-name mydog),它可能会更容易
  • 将 mydog.dog-name 转换为 (dog-name mydog) 的代码将在这里受到赞赏。或者它会因为 read-cdot 在这里激活而起作用。我相信它必须在没有括号的情况下使用。对吗?
猜你喜欢
  • 1970-01-01
  • 2021-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-26
  • 1970-01-01
  • 2015-01-08
  • 2020-09-17
相关资源
最近更新 更多