# Execute thrice only

**URL:** <https://racket.discourse.group/t/execute-thrice-only/3974>\
**Category:** Questions & Answers\
**Created:** [October 17, 2025, 2:10pm UTC](https://racket.discourse.group/t/execute-thrice-only/3974 "2025-10-17T14:10:46Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![hendrikboom3](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/hendrikboom3/32/2748_2.png) [@hendrikboom3](https://racket.discourse.group/u/hendrikboom3)\
**Post date:** [October 17, 2025, 2:10pm UTC](https://racket.discourse.group/t/execute-thrice-only/3974/1 "2025-10-17T14:10:46Z")

</div>

Let's say I want a particular piece of code to execute at most three times within the execution of a larger program.

The obvious code is something like

```scheme
(define globalcounter 3)

```

and where I have the piece of code I wrap it in

```scheme
(if ( > globalcounter 0) 
  (begin (piece-of-code) (set! globalcounter ( - globalcounter 1)))
  (complain)
)

```

I might want to have a macro.

```scheme
  (atmostthrice foo)

```

would expand to

```scheme
  (if ( > globalcounter 0) 
  (begin foo (set! globalcounter ( - globalcounter 1)))
  (complain)
)

```

Then I could use this macro if there were other things I wanted to restrict to excuting thrice:

```scheme
(thrice dothis)

```

and elsewhere

```scheme
(thrice dothat)

```

But this is wrong! (thrice dothis) and (thrice dothat) will end up sharing the same counter. If I dothis twice, I will no longer be able to count out three executions of dothat.

Somehow I need to generate a new global counter for each use of thrice.

I there any way of getting each static use of to a macro to generate a new initialized global variable?

I've thought of the following ugliness, but I don't know if it is defined to work:

```scheme
(thrice foo)

```

could expand to

```scheme
(define localglobal `,(mcons 3 #nil) )
(if ( > (mcar localglobal) 0)
     (begin foo (set-mcar! localglobal ( - (mcar localglobal) 1)
     (complain)
)

```

thereby embedding a mutable cell in the macro-expanded source code, but that seems unconscionably cute. I suspect it would fail in an implementation where compilation is separated from execution.

-- hendrik

---

<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:** [October 17, 2025, 2:51pm UTC](https://racket.discourse.group/t/execute-thrice-only/3974/2 "2025-10-17T14:51:21Z")

</div>

Your macro can use `syntax-local-lift-expression` to ask the expander to create a fresh module-level variable for you:

```scheme
#lang racket

(require syntax/parse/define)

(define-syntax-parse-rule (atmostthrice body:expr ...+)
  #:with globalcounter (syntax-local-lift-expression #'3)
  (cond
    [(= 0 globalcounter)
     (error "too many times")]
    [else
     (set! globalcounter (sub1 globalcounter))
     body ...]))

(define (try-it)
  (atmostthrice
   (displayln "run"))
  (try-it))

(with-handlers ([exn:fail? values])
  (try-it))
(try-it)

```

Note that this version is not thread-safe in the sense that it may be interrupted between the check of the counter and the update. Here's a better version:

```scheme
#lang racket

(require syntax/parse/define)

(define-syntax-parse-rule (atmostthrice body:expr ...+)
  #:with globalcounter (syntax-local-lift-expression #'(box 3))
  (let retry ()
    (define old (unbox* globalcounter))
    (cond
      [(= 0 old)
       (error "too many times")]
      [(box-cas! globalcounter old (sub1 old))
       body ...]
      [else
       (retry)])))

(define (try-it)
  (atmostthrice
   (displayln "run"))
  (try-it))

(with-handlers ([exn:fail? values])
  (try-it))
(try-it)

```

---

<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:** [October 17, 2025, 3:09pm UTC](https://racket.discourse.group/t/execute-thrice-only/3974/3 "2025-10-17T15:09:35Z")

</div>

For completeness, here's a version that uses a semaphore instead of an atomic box. You might prefer this if you expect there to be contention, because [Racket guarantees](https://docs.racket-lang.org/reference/semaphore.html):

> Semaphore waiting is _fair:_ if a thread is blocked on a semaphore and the semaphore’s internal value is non-zero infinitely often, then the thread is eventually unblocked.

(But surely you would not be doing this if you expected there to be contention!)

```scheme
#lang racket

(require syntax/parse/define)

(define-syntax-parse-rule (atmostthrice body:expr ...+)
  #:with sema (syntax-local-lift-expression #'(make-semaphore 3))
  (sync/timeout (λ ()
                  (error "too many times"))
                (handle-evt sema
                            (λ (ignored)
                              body ...))))

(define (try-it)
  (atmostthrice
   (displayln "run"))
  (try-it))

(with-handlers ([exn:fail? values])
  (try-it))
(try-it)

```

---

<div class="post-metadata">

**Author:** ![hendrikboom3](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/hendrikboom3/32/2748_2.png) [@hendrikboom3](https://racket.discourse.group/u/hendrikboom3)\
**Post date:** [October 19, 2025, 12:25am UTC](https://racket.discourse.group/t/execute-thrice-only/3974/4 "2025-10-19T00:25:55Z")

</div>

> Your macro can use `syntax-local-lift-expression` to ask the expander to create a fresh module-level variable for you:
> 
> ```scheme
> #lang racket
> 
> (require syntax/parse/define)
> 
> (define-syntax-parse-rule (atmostthrice body:expr ...+)
> #:with globalcounter (syntax-local-lift-expression #'3)
> 
> ```

# It seems that syntax-local-lift-expression does what I am asking for.

# Where can I find documentation for #:with ?

> (cond  
> [(= 0 globalcounter)  
> (error "too many times")]

# I see -- the error breaks the recursion in try-it

---

<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:** [October 19, 2025, 12:55am UTC](https://racket.discourse.group/t/execute-thrice-only/3974/5 "2025-10-19T00:55:27Z")

</div>

> [@hendrikboom3](#):
>
> Where can I find documentation for #:with ?

It is one of the _pattern directives_ supported by `syntax-parse` and related forms: the are documented in [this section of the manual](https://docs.racket-lang.org/syntax/stxparse-specifying.html#%28part._.Pattern_.Directives%29).
