# How to use \`splicing-syntax-parameterize\`?

**URL:** <https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319>\
**Category:** General\
**Created:** [September 16, 2023, 3:39pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319 "2023-09-16T15:39:52Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [September 16, 2023, 3:39pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/1 "2023-09-16T15:39:52Z")

</div>

The form `(syntax-parameterize ([id expr] ...) body-expr ...+)` binds the `ids` during the expansion of the body expressions.

I am looking for something that allows be to do the same, but can be used in an internal definition context.

My experiments with `splicing-syntax-parameterize` has however not been succesful.

What am I missing in the example below?

```scheme
#lang racket
(require racket/stxparam
         racket/splicing
         (for-syntax racket/syntax))

; SYNTAX (context)
; Expands to the either 'module-level or 'local
(define-syntax-parameter context (λ (stx) #''module-level))

; SYNTAX (local)
; Change the context to 'local.
(define-syntax (local stx)
  (with-syntax ([context (format-id stx "context")])
    #'(splicing-syntax-parameterize
          ([context (λ (stx) #''local)]))))

;;; Test Program

(context) ; -> 'module OK

(let ()
  (local) ; this is intended to rebind the `context` on the next line
  (context)) ; <- and make this call to return 'local

(context) ; -> 'module OK

```

The program currently prints:

```scheme
'module-level
'module-level
'module-level

```

---

<div class="post-metadata">

**Author:** ![usao](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/usao/32/1375_2.png) [@usao](https://racket.discourse.group/u/usao)\
**Post date:** [September 16, 2023, 3:58pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/2 "2023-09-16T15:58:06Z")

</div>

Splicing forms don’t do what you think they do—they are intended for the splicing of their body forms. I don’t think a definition-like syntax parameterization is possible without explicitly controling the expansion of the whole context ([which is what Rhombus does to implement `syntax_parameter.relet`](https://github.com/racket/rhombus-prototype/blob/8b94f3d6e63adc2e9430149ef8a582f3b7d410ad/rhombus/private/forwarding-sequence.rkt#L110)).

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [September 16, 2023, 4:02pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/3 "2023-09-16T16:02:25Z")

</div>

You have no body for `splicing-syntax-parameterize`. You have roughly:

```scheme
(context)
(let ()
  (splicing-syntax-parameterize ([context …])
    )
(context))

```

The form splices its body, not its parameterization. Does that at least help explain why it won't work as you wrote it?

---

<div class="post-metadata">

**Author:** ![benknoble](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/benknoble/32/16_2.png) [@benknoble](https://racket.discourse.group/u/benknoble)\
**Post date:** [September 16, 2023, 4:06pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/4 "2023-09-16T16:06:30Z")

</div>

One other idea: make your macro an internal-definition context:

```scheme
(define-syntax (local stx)
  (with-syntax ([context (format-id stx "context")]) ;; not sure what this is for?
    (syntax-parse stx
      [(_ e ...+) #'(splicing-syntax-parameterize ([context (λ (stx) #''local)])
                      e ...)])))

(local
 (define foo (context))
 foo)

```

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [September 16, 2023, 4:13pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/5 "2023-09-16T16:13:57Z")

</div>

@usao and @benknoble  
Yeah, only the body is spliced. I was led astray by the comment in the docs, that the body could be empty. The answer is to use `define-syntax-parameter` in the body of one of the splicing forms.

```scheme
#lang racket
(require racket/stxparam
         racket/splicing
         (for-syntax racket/syntax))

; SYNTAX (context)
; Expands to the either 'module-level or 'local
(define-syntax-parameter context (λ (stx) #''module-level))

; SYNTAX (local)
; Change the context to 'local.
(define-syntax (local stx)
  (with-syntax ([context (format-id stx "context")])
    #'(splicing-let ()
        (define-syntax-parameter context (λ (stx) #''local)))))

;;; Test Program

(context)    

(let ()
  (local)    
  (context)) 

(context)    

```

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [September 16, 2023, 4:24pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/6 "2023-09-16T16:24:28Z")

</div>

That solution requires the `(context)` to be nested inside the `local` form  
and I wanted to avoid that for my use.

I am planning to make a form `(declare-variables id ...)` form that declares that the identifiers can appear as variables in linear equation. Another form `(equation <equation>)` that introduces a linear relation betweem the variables. And finally a reference to an identifier declared as a linear relation variable, will solve the equations in order to find its value.

Example:

```scheme
(declare-vars a b)
(equation (= (+ a b) 10))
(equation (= b 4))
a ; => evaluates to 6

```

To resolve a reference to `a`, we need to know all declared linear relation variables (and they respect local scope). The idea is thus to make `declare-vars` store the currently defined linear variables using a syntax parameter. My problem was that I could not the the syntax parameter to work in a local context. I think, I am now on the right track.

---

<div class="post-metadata">

**Author:** ![LiberalArtist](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/liberalartist/32/151_2.png) [@LiberalArtist](https://racket.discourse.group/u/LiberalArtist)\
**Post date:** [September 16, 2023, 6:39pm UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/7 "2023-09-16T18:39:50Z")

</div>

> [@soegaard](#):
>
> I am planning to make a form `(declare-variables id ...)` form that declares that the identifiers can appear as variables in linear equation. Another form `(equation <equation>)` that introduces a linear relation betweem the variables. And finally a reference to an identifier declared as a linear relation variable, will solve the equations in order to find its value.
> 
> …
> 
> To resolve a reference to `a`, we need to know all declared linear relation variables (and they respect local scope). The idea is thus to make `declare-vars` store the currently defined linear variables using a syntax parameter. My problem was that I could not the the syntax parameter to work in a local context. I think, I am now on the right track.

For something like this, I would not use a syntax parameter that way.

Instead, you could have `(declare-variables id ...)` expand to `(begin (define-syntax id (make-variable)) ...)` and use `syntax-local-value` (or the [`static`](https://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#%28def._%28%28lib._syntax%2Fparse..rkt%29._static%29%29) syntax class) to recognize identifiers bound as variables. Then all handling of scope is taken care of for you by Racket.

Depending on the complexity of your project, you might also take a look at the [`ee-lib`](https://docs.racket-lang.org/ee-lib/) library, which supports writing macro-extensible DSLs. I still haven't gotten around to using the library for anything large, but I have implemented a similar approach by hand based on [Alexis' blog posts](https://lexi-lambda.github.io/blog/2018/09/13/custom-core-forms-in-racket-part-ii-generalizing-to-arbitrary-expressions-and-internal-definitions/) before the library and paper existed.

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [September 17, 2023, 10:59am UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/8 "2023-09-17T10:59:11Z")

</div>

> [@LiberalArtist](#):
>
> For something like this, I would not use a syntax parameter that way.
> 
> Instead, you could have `(declare-variables id ...)` expand to `(begin (define-syntax id (make-variable)) ...)` and use `syntax-local-value` (or the [`static`](https://docs.racket-lang.org/syntax/Library_Syntax_Classes_and_Literal_Sets.html#%28def._%28%28lib._syntax%2Fparse..rkt%29._static%29%29) syntax class) to recognize identifiers bound as variables. Then all handling of scope is taken care of for you by Racket.

The problem is that when a variable is referenced, its value depends on the other variables in scope at the place of reference. Keeping track of the current set of variables in scope (or the current set of equations) needs a bit more.

> [@LiberalArtist](#):
>
> Depending on the complexity of your project, you might also take a look at the [`ee-lib`](https://docs.racket-lang.org/ee-lib/) library, which supports writing macro-extensible DSLs.

This looks interesting. Thanks for the pointer.

What does the `ee` stand for. My thoughts went to "electrical engineering".

---

<div class="post-metadata">

**Author:** ![usao](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/usao/32/1375_2.png) [@usao](https://racket.discourse.group/u/usao)\
**Post date:** [September 18, 2023, 5:45am UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/9 "2023-09-18T05:45:19Z")

</div>

I think `ee` stands for “Embedded Expanders.”

---

<div class="post-metadata">

**Author:** ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)\
**Post date:** [September 18, 2023, 11:47am UTC](https://racket.discourse.group/t/how-to-use-splicing-syntax-parameterize/2319/10 "2023-09-18T11:47:16Z")

</div>

The following example defines to forms `declare` and `variables`.

The form `declare` is used to declare identifiers (to have some property).

The form `variables` expands to a list of all declared variables in scope,  
where the form appears.

The form `declare` can occur multiple times in the same scope.

Suggestions?

If I could use the same expansion for `declare` for all applications  
in the same scope, the definition of `declare` could be simplified.  
That ties in with the original question: Is there an "syntax-parameterize"  
suited for an internal definition context?

```scheme
#lang racket
(require racket/stxparam racket/splicing)
(require (for-syntax racket/base syntax/parse racket/syntax syntax/stx))
(require (for-syntax (for-syntax syntax/parse racket/base)))

;;; UTILITIES

(begin-for-syntax
  ; SYNTAX (push*! id expr)
  ; The result of `expr` must be a list of identifiers.
  ; The identifiers pushed onto the list held by `id`.
  (define-syntax (push*! stx)
    (syntax-parse stx [(_ id:id e:expr)
                       #'(let ([vs e])
                           (for ([v (in-list (stx->list vs))])
                             (set! id (cons v id))))])))

;;; DECLARED VARIABLES

(begin-for-syntax
  ;; Module Level Variables
  (define module-level-declared-variables '()) ; list of identifiers
  (define (add-module-level-variables! ids)
    (push*! module-level-declared-variables (stx->list ids)))
  ;; Local Variables
  ;; - each internal definition context is given an index
  (define intdefs (make-hasheq))
  ;; - each index is associated to a list of declared names
  (define local-variables (make-hash))
  
  (define (new-intdef? intdef) (not (hash-has-key? intdefs intdef)))
  (define (index-of-intdef intdef) (hash-ref! intdefs intdef (hash-count intdefs)))
  (define (get-local-variables index) (hash-ref local-variables index))
  (define (add-local-variable! index id)
    (hash-update! local-variables index (λ (old-vars) (cons id old-vars)) '()))
  (define (add-local-variables! index vars)
    (for ([id (stx->list vars)]) (add-local-variable! index id))))

;; SYNTAX PARAMETER variables
;; When applied expands to a list with the declared variables in scope.
(define-syntax-parameter variables
  (λ (stx) (with-syntax ([(id ...) module-level-declared-variables])
             #''(id ...))))

;; SYNTAX (declare id ...)
;; Declare that the variables id ... are "declared" variables.
(define-syntax (declare stx)
  (syntax-parse stx
    [(_declare id ...)
     ; - the expansion on `declare` depends on where it is used.
     (define ctx (syntax-local-context))
     (case ctx 
       [(module)
        (add-module-level-variables! #'(id ...))
        #'(begin)]
       [(expression)
        (raise-syntax-error 'declare "not allowed in an expression context" stx)]
       [else ; local context
        ; - find the local variables in outside this scope
        (define vars (local-expand
                      (with-syntax ([variables (syntax-local-get-shadower #'variables)])
                        #'(variables))
                      ctx '()))
        ; - if we are in a new scope, we must reparameterize `variables`
        ; - if not simply add the new identifiers 
        (define new-scope? (new-intdef? ctx))
        (define index (index-of-intdef ctx))
        (cond
          [new-scope?
           (add-local-variables! index #'(id ...))
           (with-syntax ([variables (format-id stx "variables")]
                         [(_quote (outer-id ...)) vars]
                         [index index]
                         [.... #'(... ...)])
             #'(define-syntax-parameter variables
                 (λ (stx)
                   (with-syntax ([(local-id ....) (get-local-variables index)])
                     #''(local-id .... outer-id ...)))))]
          [else
           (add-local-variables! index #'(id ...))
           #'(begin)])])]))
        

(variables) ; ()
(declare a b)
(variables) ; (a b )
(let ()
  (declare c d)  
  (displayln (variables)) ; ( i j c d a b g h)
  (let ()
    (declare e f)
    (displayln (variables))) ; (e f i j c d a b g h)
  (declare i j)
  (displayln (variables))) ; (i j c d a b g h)
(variables) ; (a b )
(declare g h)
(variables) ; (a b g h) 

```
