# Cond-expand in Racket

**URL:** <https://racket.discourse.group/t/cond-expand-in-racket/4000>\
**Category:** Questions & Answers\
**Created:** [November 8, 2025, 8:34pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000 "2025-11-08T20:34:41Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 8, 2025, 8:34pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/1 "2025-11-08T20:34:41Z")

</div>

Hi,

i have some code, not written by me, i want to port to Racket and it uses `cond-expand` (see [SRFI 0](https://srfi.schemers.org/srfi-0/srfi-0.html)) to adapt to each scheme implementation,for example Chicken or Guile had a feature `guile` that exists when guile compiler is running, does Racket has something like that?

example with Guile scheme:

```scheme
scheme@(guile-user)> (cond-expand (guile "Guile"))
$1 = "Guile"

```

Best regards,

---

<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:** [November 8, 2025, 9:37pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/2 "2025-11-08T21:37:20Z")

</div>

I don't know of a stand-alone implementation of SRFI 0 for Racket. If you are willing to accept the package dependency, I think the best off-the-shelf option would be the `cond-expand` from R7RS, which you can access using `(require (only-in r7rs cond-expand))`. For example:

```scheme
#lang racket/base
(require (only-in r7rs cond-expand))
(cond-expand
 [(not (not (or (and racket) bogus)))
  #t]
 [else
  does-not-compile])

```

The R7RS implementation recognizes the following features as supported:

> <https://github.com/lexi-lambda/racket-r7rs/blob/ffc65dad67c0d3880b5284da3a42e95828d7e8d3/r7rs-lib/private/cond-expand.rkt#L11-L13>

If you need other features, or if you want to avoid the dependency, it would also be reasonable to write a minimal `cond-expand` implementation specific to your needs.

You might also be interested in the [convention](https://docs.racket-lang.org/r6rs/libpaths.html) of putting implementation-specific code in files with the extension `.mzscheme.ss` or `.mzscheme.sls`.

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 9, 2025, 8:53am UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/3 "2025-11-09T08:53:11Z")

</div>

That seems good. It is R7RS scheme, so portable.I even did not know there was this library in Racket, should be put in the manual page in my opinion or even proposed as language in the GUI.

Of course this is strange because i have to import a Racket R7RS package in code before testing i'm in Racket ! or in other scheme . `cond-expand` should be ,by default in Racket.The fact seems to be the code i'm porting try to define module for Guile,Chicken in the same file using `cond-expand` ! This is a bit too much. It should have be more 'readable' to have different scheme implementation for each scheme dialect.

But with this solution i could keep the code of all implementation in the same file, that's interesting if i go back later on this code to test it on a different scheme implementation.

About the SRFI 0 i try to put the source code, but i can not get a result, i do not see where the conditional is in the code? 🤔 If i try to detect for example a special racket feature such as `current-namespace` or `version` it does not worked with SRFI 0 source code.

Thank you.

---

<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:** [November 13, 2025, 12:20am UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/4 "2025-11-13T00:20:57Z")

</div>

> [@damien\_mattei](#):
>
> About the SRFI 0 i try to put the source code, but i can not get a result, i do not see where the conditional is in the code? 🤔

The sample implementation in SRFI 0 “assumes that all existent features are built-in (here we assume `srfi-0` and `srfi-5` are present)”. The only conditional in the code is the pattern-matching of `syntax-rules`. The implementation handles `and`, `or`, and `not` forms by recursively expanding to `cond-expand`, so any supported feature clause will eventually match one of these cases:

```scheme
    ((cond-expand (srfi-0 body ...) more-clauses ...)
       (begin body ...))
    ((cond-expand (srfi-5 body ...) more-clauses ...)
       (begin body ...))

```

If there is no supported feature clause, the `cond-expand` form will instead reduce to one of these cases:

```scheme
    ((cond-expand) (syntax-error "Unfulfilled cond-expand"))
    ((cond-expand (else body ...))
     (begin body ...))

```

This is obviously a very awkward way to implement `cond-expand`, but, at the time of SRFI 0, `syntax-rules` was the only portable way to write macros. The perspective of the SRFI system, especially in early SRFIs, is that a SRFI is a _request for implementation_, with the sample implementation being truly just a sample. Scheme implementers are requested to implement the interface using their implementation's specific features. SRFI 0 is a particular example of a case when distributing the sample implementation unmodified would be essentially useless.

> [@damien\_mattei](#):
>
> If i try to detect for example a special racket feature such as `current-namespace` or `version` it does not worked with SRFI 0 source code.

One of the curious aspects of SRFI 0 is that it doesn't define a registry of feature symbols. I think other SRFIs may have done so, at least to a limited extent. The list recognized by Alexis’ R7RS Small implementation comes from [R7RS Small Appendix B](https://standards.scheme.org/corrected-r7rs/r7rs-Z-H-11.html#TAG:__tex2page_chap_B), but that appendix explicitly _does not_ require that `cond-expand` recognize all of the feature identifiers corresponding to provided features (it merely forbids recognition of any feature identifier for a feature that is _not_ provided), and Alexis’ implementation does not seem to try to be comprehensive, especially when it comes to the open-ended sets of feature identifiers.

I don't know of any specification that defines `current-namespace` or `version` as `cond-expand` features.

Overall, I do not recommend `cond-expand` as a way of structuring portable Scheme, and I recommend it even less as a way of structuring Racket. I would approach it as a construct you need to stub out so you can port code that uses it, not as a construct for making code more portable.

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 13, 2025, 8:17pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/5 "2025-11-13T20:17:55Z")

</div>

Hello Philip and thank you for your long answer,  
i better understand 'cond-expand' now enough to write a version that match with Racket even if i'm not sure to understand the scheme macros, because often when i used them it seems i have still something to learn about them.

I could add a clause in cond-expand like that for racket:

```scheme
 ((cond-expand (racket body ...) more-clauses ...)
       (begin body ...))

```

so the whole 'cond-expand' of srfi-0 would now be for racket:

```scheme
(define-syntax cond-expand
  (syntax-rules (and or not else srfi-0 srfi-5)
    ((cond-expand) (syntax-error "Unfulfilled cond-expand"))
    ((cond-expand (else body ...))
     (begin body ...))
    ((cond-expand ((and) body ...) more-clauses ...)
     (begin body ...))
    ((cond-expand ((and req1 req2 ...) body ...) more-clauses ...)
     (cond-expand
       (req1
         (cond-expand
           ((and req2 ...) body ...)
           more-clauses ...))
       more-clauses ...))
    ((cond-expand ((or) body ...) more-clauses ...)
     (cond-expand more-clauses ...))
    ((cond-expand ((or req1 req2 ...) body ...) more-clauses ...)
     (cond-expand
       (req1
        (begin body ...))
       (else
        (cond-expand
           ((or req2 ...) body ...)
           more-clauses ...))))
    ((cond-expand ((not req) body ...) more-clauses ...)
     (cond-expand
       (req
         (cond-expand more-clauses ...))
       (else body ...)))
    ((cond-expand (srfi-0 body ...) more-clauses ...)
       (begin body ...))
    ((cond-expand (srfi-5 body ...) more-clauses ...)
       (begin body ...))
    ((cond-expand (racket body ...) more-clauses ...)
       (begin body ...))
    ((cond-expand (feature-id body ...) more-clauses ...)
       (cond-expand more-clauses ...))))

```

and running it like that:

```scheme
(cond-expand
 (racket "Racket")
 (else "je sais pas"))

```

would return the correct result:

`"Racket"`

Perheaps i will use this modified 'cond-expand' but anyway, as i must be from the start already in a Racket module it is like when the [Dupont and Dupond say "Et je dirais même plus ... c'est du Racket."](https://tintinbd.wordpress.com/2015/05/05/je-dirais-meme-plus/)

You're right, 'cond-expand' is not the best way to make code portable, but it is the way this third party code is written (not by me).

Damien

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 13, 2025, 8:25pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/6 "2025-11-13T20:25:13Z")

</div>

> [@damien\_mattei](#):
>
> ```scheme
> (cond-expand
> (racket "Racket")
> (else "je sais pas"))
> 
> ```

but then it would not works with another scheme implementation,

forget my last post, 😅 my solution is wrong... still i have to learn about macros

---

<div class="post-metadata">

**Author:** ![rogert](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/rogert/32/2474_2.png) [@rogert](https://racket.discourse.group/u/rogert)\
**Post date:** [November 13, 2025, 10:52pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/7 "2025-11-13T22:52:27Z")

</div>

Regarding identifiers for implementations and "features", there is [https://registry.scheme.org/](https://registry.scheme.org/)

---

<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:** [November 14, 2025, 1:04am UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/8 "2025-11-14T01:04:09Z")

</div>

> [@damien\_mattei](#):
>
> > [@damien\_mattei](#):
> >
> > ```scheme
> > (cond-expand
> > (racket "Racket")
> > (else "je sais pas"))
> > 
> > ```
> 
> but then it would not works with another scheme implementation,

A paradox of `cond-expand` is that it cannot be portably implemented using `syntax-rules`, because the supported feature symbols—which are inherently implementation-specific—have to be hard-coded into the `syntax-rules` patterns.

Basically, you need to use some other portability technique to arrange for a suitable definition of `cond-expand` to be present for each Scheme system. That's one way this might help:

> [@LiberalArtist](#):
>
> You might also be interested in the [convention](https://docs.racket-lang.org/r6rs/libpaths.html) of putting implementation-specific code in files with the extension `.mzscheme.ss` or `.mzscheme.sls`.

(If you have procedural macros, which were not standardized when SRFI 0 was written, it is more feasable to write a portable `cond-expand`, but my recommendation is to just do whatever is easiest for porting the concrete code at hand.)

---

<div class="post-metadata">

**Author:** ![damien\_mattei](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/damien_mattei/32/2706_2.png) [@damien\_mattei](https://racket.discourse.group/u/damien_mattei)\
**Post date:** [November 14, 2025, 7:50am UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/9 "2025-11-14T07:50:10Z")

</div>

Yes ,I understand a bit all that but the solution you provides is already good and used in the code now.  
I'm trying to port to Racket the SRFI 110 implementation, not really for sweet expressions, i dislike that, but because the code has been written one year after the one of SRFI 105 and it integrates a perheaps better curly infix parser. As i already fixed things in SRFI 105 previous code i find interesting the SRFI 110 code that implements both,sweet,curly and neoteric expressions in the same code in a more modern and complete way perheaps (to be checked and tested).

See: [https://srfi.schemers.org/srfi-110/kernel.scm](https://srfi.schemers.org/srfi-110/kernel.scm)  
there is even a latest version of kernel.scm in this archive:  
[Download readable-1.0.10.tar.gz (Readable Lisp S-expressions)](https://sourceforge.net/projects/readable/files/readable-1.0.10.tar.gz/download)

you can then see the use of 'cond-expand' i working on, of course i can get rid of all that,and anyway in modern code i started to put all this code in a Racket module, so there is a bit of non-sense to keep the 'cond-expand' in a racket module, i know that 🤷 . Perheaps the only interest of 'cond-expand' is if later the modified code has to be ported back to Guile (i think readable had been made for Guile first) or to another scheme such Chicken as i see a few support for this scheme for this implementation too.I already have an old version of SRFI 105 for Scheme+ for Guile that i should upgrade one day.

---

<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:** [November 14, 2025, 6:48pm UTC](https://racket.discourse.group/t/cond-expand-in-racket/4000/10 "2025-11-14T18:48:49Z")

</div>

How is one supposed to use these identifiers in a program?

-- hendrik
