Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Racket 如何访问包含省略号的`~optional`中的语法类属性? TL;博士_Racket - Fatal编程技术网

Racket 如何访问包含省略号的`~optional`中的语法类属性? TL;博士

Racket 如何访问包含省略号的`~optional`中的语法类属性? TL;博士,racket,Racket,我正在尝试将可选省略号(~optional datum:my class…扩展为使用my class属性的表单,例如:#'(list datum.attr…) 但由于表单是可选的,当它不存在时,它会解析为#f,省略号模式不喜欢: ;; ?: attribute contains non-list value ;; value: #f 我尝试使用~ optional的:defaults参数,如下所示: (~optional datum:my-class ... #:defaults ([(d

我正在尝试将可选省略号
(~optional datum:my class…
扩展为使用
my class
属性的表单,例如:
#'(list datum.attr…

但由于表单是可选的,当它不存在时,它会解析为
#f
,省略号模式不喜欢:

;; ?: attribute contains non-list value
;;   value: #f
我尝试使用
~ optional
:defaults
参数,如下所示:

(~optional datum:my-class ... #:defaults ([(datum 1) null]))
我通过使用以下技巧实现了这一点:

(~optional datum:my-class ...)

#'(list #,@(if (attribute datum) #'(datum.attr ...) #'()))
我在想是否有更好的办法

完整的可运行示例 我尽量把它控制在最低限度。检查测试子模块。 要查看问题,请取消注释
parse bag
的四种实现之一,然后运行
raco test file.rkt

#lang racket/base

(provide parse-bag)

(require
  (for-syntax racket/base syntax/parse)
  syntax/parse)

(struct bag (label objects) #:transparent)
(struct object (name) #:transparent)

(begin-for-syntax
  (define-syntax-class obj-exp
    #:datum-literals (object name)
    (pattern (object (name <name>:str))
             #:with result #'(object <name>))))

;; IMPLEMENTATION ONE
;; DESC: The naive but failing approach
;; UNCOMMENT TO TEST
#;(define-syntax (parse-bag stx)
  (syntax-parse stx
      #:datum-literals (label objects)
      [(_ (label <label>:str)
          (~optional (objects <object>:obj-exp ...)))
       #'(bag <label>
              (list <object>.result ...))]))
;; ?: attribute contains non-list value
;;   value: #f


;; IMPLEMENTATION TWO
;; DESC: adding defaults will fail too
;; UNCOMMENT TO TEST
#;(define-syntax (parse-bag stx)
  (syntax-parse stx
      #:datum-literals (label objects)
      [(_ (label <label>:str)
          (~optional (objects <object>:obj-exp ...)
                     #:defaults ([(<object> 1) null]))) ; (HERE)
       #'(bag <label>
              (list <object>.result ...))]))
;; ?: attribute contains non-list value
;;   value: #f


;; IMPLEMENTATION THREE
;; DESC: it won't fail when not using syntax-class attributes
;; UNCOMMENT TO TEST
#;(define-syntax (parse-bag stx)
  (syntax-parse stx
      #:datum-literals (label objects)
      [(_ (label <label>:str)
          (~optional (objects <object>:obj-exp ...)
                     #:defaults ([(<object> 1) null])))
       #'(bag <label>
              (list <object> ...))])) ; (HERE)
;; name: unbound identifier


;; IMPLEMENTATION FOUR
;; DESC: it works, but I find it ugly
;; UNCOMMENT TO TEST
#;(define-syntax (parse-bag stx)
  (syntax-parse stx
      #:datum-literals (label objects)
      [(_ (label <label>:str)
          (~optional (objects <object>:obj-exp ...)))
       #`(bag <label>
              (list #,@(if (attribute <object>)
                           #'(<object>.result ...)
                           #'())))]))


(module+ test (require rackunit)

(check-equal?
  (parse-bag
    (label "Biscuits")
    (objects (object (name "Cookie"))
             (object (name "Brownie"))))

  (bag "Biscuits"
        (list (object "Cookie")
              (object "Brownie"))))

(check-equal?
  (parse-bag (label "Sweets"))
  (bag "Sweets" '()))

)
#朗格球拍/球座
(提供解析包)
(要求
(用于语法racket/base语法/parse)
语法/语法分析)
(结构包(标签对象)#:透明)
(结构对象(名称)#:透明)
(从语法开始
(定义语法类obj exp
#:基准文字(对象名称)
(图案(对象(名称:str))
#:结果为#'(对象)))
;; 实施一
;; 描述:天真但失败的方法
;; 取消对测试的注释
#;(定义语法(解析包stx)
(语法解析stx)
#:基准文字(标签对象)
[((标签:str)
(~可选(对象:obj exp…)
#"(包)
(列表、结果…))
;; ?: 属性包含非列表值
;;   值:#f
;; 实施二
;; DESC:添加默认值也会失败
;; 取消对测试的注释
#;(定义语法(解析包stx)
(语法解析stx)
#:基准文字(标签对象)
[((标签:str)
(~可选(对象:obj exp…)
#:默认值([(1)null]);(此处)
#"(包)
(列表、结果…))
;; ?: 属性包含非列表值
;;   值:#f
;; 实施三
;; DESC:不使用语法类属性时不会失败
;; 取消对测试的注释
#;(定义语法(解析包stx)
(语法解析stx)
#:基准文字(标签对象)
[((标签:str)
(~可选(对象:obj exp…)
#:默认值([(1)null]))
#"(包)
(名单…);(这里)
;; 名称:未绑定标识符
;; 实施四
;; 这很管用,但我觉得很难看
;; 取消对测试的注释
#;(定义语法(解析包stx)
(语法解析stx)
#:基准文字(标签对象)
[((标签:str)
(~可选(对象:obj exp…)
#`(袋
(列表#,@(如果(属性))
#“(.结果…)
#'())))]))
(模块+测试(需要机架单元)
(检查是否相等?
(解析包
(贴上“饼干”标签)
(对象(对象(名称为“Cookie”))
(对象(名称为“布朗尼”))
(袋装“饼干”
(列表(对象“Cookie”)
(对象“布朗尼”))
(检查是否相等?
(包装袋(标签为“糖果”))
(包"糖果"())
)
使用
#:默认值时,需要指定属性:

(~optional <object>:obj-exp ... #:defaults ([(<object>.result 1) null]))
(~可选:obj exp…#:默认值([(.result 1)null]))
完整代码:
(定义语法(解析包stx)
(语法解析stx)
#:基准文字(标签对象)
[((标签:str)
(~可选(对象:obj exp…)
#:默认值([(.result 1)null]);+此处的属性
#"(包)
(列表、结果…);现在它工作了!

另一种方法是将省略号的用法移动到语法类,如在这个问题中:

有两类策略可以修复“attribute value is false”错误:

  • 放置默认值或备选值,以便属性永远不会为false

    (a) 与
    #一起使用:默认值

    (b) 使用,可能与

    (c) 使用具有多个模式的语法类

  • 处理在主体中为false的属性

    (a) 使用及

    (b) 使用

  • 1(a) 问题中的实现2和3,以及Jérôme回答中的代码,都与
    #:默认值一起使用,因此它们都试图用1(a)来修复它

    Jérôme的回答表明了这一点的正确使用。要点是,如果使用像
    .result
    这样的属性,则需要为
    .result
    指定默认值,而不仅仅是

    但是,如果需要使用
    obj exp
    类中的多个属性,则会出现这种情况的一个缺点。这将要求您为每一项指定默认值:

    (~optional (objects <object>:obj-exp ...)
               #:defaults ([(<object>.result 1) null]
                           [(<object>.x 1) null]))
    
    1(c) 然而,正如你所说,这看起来有点难看。它还有另一个问题。如果它本身在省略号下,则会发生故障,因为省略号不会在or中携带其效果

    这就是2(b)存在的原因。您可以使用以下命令,而不是使用
    ,@(如果…)

    (~? (<object>.result ...) ())
    
    (~?(.result…)
    
    这不太管用,但它的这种变体可以:

    (~? (list <object>.result ...) (list))
    
    (~?(list.result…)(list))
    
    在实施方案4的变体中使用:

    (define-syntax (parse-bag stx)
      (syntax-parse stx
        #:datum-literals (label objects)
        [(_ (label <label>:str)
            (~optional (objects <object>:obj-exp ...)))
         #`(bag <label>
                (~? (list <object>.result ...) (list)))]))
    
    (定义语法(解析包stx)
    (语法解析stx)
    #:基准文字(标签对象)
    [((标签:str)
    (~可选(对象:obj exp…)
    #`(袋
    (?(list.result…(list))))
    
    太棒了!现在我知道了很多不同的方法来解决一些语法分析问题,使用
    ~?
    ~parse
    ,这是我以前不知道的。谢谢:)
    (~or (objects <object>:obj-exp ...)
         (~and (~seq) (~parse (<object>:obj-exp ...) null)))
    
    (define-splicing-syntax-class maybe-objects
      #:datum-literals (objects)
      [pattern (objects <object>:obj-exp ...)]
      [pattern (~seq) #:with (<object>:obj-exp ...) null])
    
    #,@(if (attribute <object>)
           #'(<object>.result ...)
           #'())
    
    (~? (<object>.result ...) ())
    
    (~? (list <object>.result ...) (list))
    
    (define-syntax (parse-bag stx)
      (syntax-parse stx
        #:datum-literals (label objects)
        [(_ (label <label>:str)
            (~optional (objects <object>:obj-exp ...)))
         #`(bag <label>
                (~? (list <object>.result ...) (list)))]))