Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Curly brackets {} to replace 'begin' in Racket

Tags:

scheme

racket

Is it possible to have a macro to use curly brackets {} to indicate a block of statments, so as to replace the 'begin' keyword. Hence, instead of:

(if (condition)
    (begin 
        (statement1)
        (statement2)
        (statement3)
        (statement4))
    (else-statement))

we may use:

(if (condition) {
        (statement1)
        (statement2)
        (statement3)
        (statement4) }
    (else-statement))

How can this be accomplished? Thanks for your answers.

like image 444
rnso Avatar asked Jul 14 '16 08:07

rnso


People also ask

What are {} used for?

Brackets are used to insert explanations, corrections, clarifications, or comments into quoted material. Brackets are always used in pairs; you must have both an opening and a closing bracket.

What do the curly brackets mean in code?

In programming, curly braces (the { and } characters) are used in a variety of ways. In C/C++, they are used to signify the start and end of a series of statements. In the following expression, everything between the { and } are executed if the variable mouseDOWNinText is true. See event loop.

What do curly brackets do in R?

The curly brackets are used to denote a block of code in a function. So, say we need a function to calculate the standard error we might do this. The square brackets are used to subset vectors and data frames.

What do curly brackets mean in Lua?

There are no lists or dictionaries in Lua, but a "table" type which serves as both. So curly brackets are used as a table constructor.


1 Answers

This is completely possible, and there are several ways to do it. (Quick note before I start, I'm going to use block instead of begin because it behaves better with internal definitions.)

Method 1: Re-defining #%app

One slightly hack-y way is to redefine what function application means so that curly-braces are treated specially. You can do this by defining an #%app macro:

#lang racket
(require racket/block syntax/parse/define (prefix-in - racket))
;; This #%app macro redefines what function application means so that
;; { def-or-expr ... } expands into (block def-or-expr ...)
;; Otherwise it uses normal function application
(define-syntax-parser #%app
  [{_ def-or-expr:expr ...}
   #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
   ;; group them in a block
   #'(block def-or-expr ...)]
  [(_ f:expr arg ...)
   #:when (not (equal? #\{ (syntax-property this-syntax 'paren-shape)))
   ;; expand to the old #%app form, from (prefix-in - racket)
   #'(-#%app f arg ...)])
;; using it:
(define (f x)
  (if (< 5 x) {
        (define y (- x 5))
        (f y)
      }
      x))
(f 1) ; 1
(f 5) ; 5
(f 6) ; 1
(f 10) ; 5
(f 11) ; 1

Method 2: Extending the Reader

Another way would be to define a new #lang language and extend the readtable with a different entry for the { character. Let me go and do that ...

To define a #lang language, you need to put the reader implementation in your-language/lang/reader.rkt. Here that's curly-block/lang/reader.rkt, where the curly-block directory is installed as a single-collection package (raco pkg install path/to/curly-block).

curly-block/lang/reader.rkt

;; s-exp syntax/module-reader is a language for defining new languages.
#lang s-exp syntax/module-reader
racket
#:wrapper1 (lambda (th)
             (parameterize ([current-readtable (make-curly-block-readtable (current-readtable))])
               (th)))

;; This extends the orig-readtable with an entry for `{` that translates
;; { def-or-expr ... } into (block def-or-expr ...)
(define (make-curly-block-readtable orig-readtable)
  (make-readtable orig-readtable
    #\{ 'terminating-macro curly-block-proc))

;; This is the function that the new readtable will use when in encounters a `{`
(define (curly-block-proc char in src ln col pos)
  ;; This reads the list of things ending with the character that closes `char`
  ;; The #f means it uses the racket reader for the first step, so that `{`
  ;; uses the normal behavior, grouping expressions into a reader-level list
  (define lst (read-syntax/recursive src in char #f))
  (cons 'block lst))

Using it:

#lang curly-block
(require racket/block)
(define (f x)
  (if (< 5 x) {
        (define y (- x 5))
        (f y)
      }
      x))
(f 1) ; 1
(f 5) ; 5
(f 6) ; 1
(f 10) ; 5
(f 11) ; 1
like image 98
Alex Knauth Avatar answered Oct 26 '22 09:10

Alex Knauth