macros - 在 Racket 类函数中使用点表示法

标签 macros scheme racket

我有以下类(class),效果很好:

(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) ...)))

错误在哪里以及如何纠正?

最佳答案

要使用这样的点表示法,您需要定义一种新的 #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")

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

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

#lang racket

(provide (all-from-out racket))

这还没有定义#lang。但要尝试一下,您可以转到 DrRacket 的"file"菜单,单击“包管理器”,然后在“包源”字段中输入 send-dot 目录的路径。完成此操作后,您应该能够在另一个文件中使用 #lang s-exp send-dot,就像 #langracket 一样。

要为该语言定义阅读器并使其成为真正的#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)

现在您应该能够像 #langracket 一样使用 #lang send-dot

现在您还需要做两件事。一、打开read-cdot选项,以便将 (o.method args ...) 转换为 ((#%dot o method) args ...),并且二,定义一个 #%dot 宏,使得 ((#%dot o method) args ...) 相当于 (send o method args ...)

首先,您可以使用#:wrapper1选项,使用parameterizeread-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/应用 o 方法参数)).

#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")

关于macros - 在 Racket 类函数中使用点表示法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39224842/

相关文章:

scheme - 将字符串列表合并为逗号分隔的字符串

macros - Clojure 如何在源文件中扩展宏与 Repl

scope - 在本地环境中定义和访问变量

c++ - 创建一个类似 Q_PROPERTY 的宏并提取 __VA_ARGS__

scheme - printf %6.2f 是方案还是 Racket ?

recursion - 需要帮助找到列表中的第二大数字。 Racket

haskell - 有没有针对不懂 Lisp 的人的 Template Haskell 教程?

list - 方案拆分操作不起作用

data-structures - 无限数据结构有哪些引人注目的用例?

performance - 如何确定为什么我的 Racket 代码运行如此缓慢?