- 
          
- 
                Notifications
    You must be signed in to change notification settings 
- Fork 3
Open
Description
Many functions accept a lot of optional "boolean" keyword arguments. These arguments are known as flags. As an example:
(define (string-trim s #:left? [left? #f] #:right? [#:right? #f])
  (list s left? right?))
has two flags: #:left? and #:right?.
The function then can be called with:
(string-trim " 1 2 3 " #:left? #t #:right? #t)
Flaggable #%app allows users to instead write:
(string-trim " 1 2 3 " #:left? #:right?)
That is, a keyword argument that doesn't have a "value" will default the value to #t. Explicit "value" is still supported.
This does come at a cost: all keyword arguments must be specified after positional arguments to avoid ambiguity. Without this restriction, it's hard to tell whether:
(f #:a 1)
is meant to be itself or:
(f 1 #:a #t)
Macro
#lang racket 
(require syntax/parse/define
         (only-in racket [#%app racket:#%app]))
(begin-for-syntax
  (define-splicing-syntax-class arg/keyword
    #:attributes (k v)
    ;; first case: something like #:a 1
    (pattern {~seq k:keyword v:expr})
    ;; second case: something like #:a.
    (pattern {~seq k:keyword}
             #:with v #'#t)))
(define-syntax-parse-rule (#%app f arg/no-keyword:expr ... arg/keyword:arg/keyword ...)
  (racket:#%app f arg/no-keyword ... {~@ arg/keyword.k arg/keyword.v} ...))
Note: inspired by https://www.reddit.com/r/Racket/comments/oytknk/keyword_arguments_without_values/h7w67dd/, though I had thought of doing it before, too.
Example usage:
(define (f c #:a [a #f] #:b [b #f])
  (list c a b))
(f 0 #:a #:b)       ;=> '(0 #t #t)
(f 0 #:a)           ;=> '(0 #t #f)
(f 0 #:b)           ;=> '(0 #f #t)
(f 0 #:a 10 #:b)    ;=> '(0 10 #t)
(f 0 #:a #:b 20)    ;=> '(0 #t 20)
(f 0 #:a 10 #:b 20) ;=> '(0 10 20)
(f 0)               ;=> '(0 #f #f)
#;(f #:a 0 1)
; #%app: expected keyword
;   parsing context: 
;    while parsing arg/keyword in: 1
Before code
(f 0 #:a #t #:b #t) ;=> '(0 #t #t)
(f 0 #:a #t)        ;=> '(0 #t #f)
(f 0 #:b #t)        ;=> '(0 #f #t)
(f 0 #:a 10 #:b #t) ;=> '(0 10 #t)
(f 0 #:a #t #:b 20) ;=> '(0 #t 20)
(f 0 #:a 10 #:b 20) ;=> '(0 10 20)
(f 0)               ;=> '(0 #f #f)
Licence
MIT / CC-BY 4.0
bennn and shhyou
Metadata
Metadata
Assignees
Labels
No labels