# Apply values to a procedure

**URL:** <https://racket.discourse.group/t/apply-values-to-a-procedure/3506>\
**Category:** Questions & Answers\
**Created:** [January 21, 2025, 5:15pm UTC](https://racket.discourse.group/t/apply-values-to-a-procedure/3506 "2025-01-21T17:15:07Z")\
**Posts on this page:** 1\
**Showing post:** 22

<div class="post-metadata">

**Author:** ![countvajhula](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/countvajhula/32/65_2.png) [@countvajhula](https://racket.discourse.group/u/countvajhula)\
**Post date:** [January 27, 2025, 5:06am UTC](https://racket.discourse.group/t/apply-values-to-a-procedure/3506/22 "2025-01-27T05:06:16Z")

</div>

I think you've correctly identified the problem. It has to do with the relationship between the reading and expansion stages, and the order of expansion.

The `$nfx$` macros are inserted into the user syntax at the _read_ stage, before we know anything yet about the _meaning_ of the program.

At the expansion stage, the way I look at it, syntax is transformed in relation to unspecified meaning. That is, expressions are transformed according to rules of the form, "this syntax means what that syntax means." The ultimate meaning of expressions is finally determined when the expressions are _evaluated_ after being expanded and compiled. Yet, the transformations during expansion are aware of meaning, at least in the sense that, unlike reading, expansion rules are _context sensitive_ (cf. [this great article](https://parentheticallyspeaking.org/articles/bicameral-not-homoiconic/) by Shriram).

At this expansion stage, to take context into account, macros are expanded "outside in." The outermost macros get to define the meaning of the contained syntax, delegating to any additional macros as needed by expanding to them. So even though the `$nfx$` is independently inserted at the reading stage in both places --- the outer one and the nested one --- when it gets to expansion, these are not expanded independently. Instead, the outer `$nfx$` expands first to generate the Qi expression. This expression is then expanded by Qi (specifically by the `flow` macro which specifies the Qi language). And finally, the inner `$nfx$` macro is expanded.

During the Qi expansion stage, if we don't tell Qi about `$nfx$`, it just assumes it is a function and uses it as a function (for example, it might try to `compose` it with other functions in the expansion). This, as you also mentioned encountering elsewhere, usually leads to a syntax error.

By using `define-qi-foreign-syntaxes`, we tell Qi to treat `$nfx$` as a "foreign" macro, that is, a form that isn't actually a function but has the same syntax as a function and is typically used as if it were a function. Racket's `and` is a good example of this (so much so, that people are usually confused when they find they can't use `and` in higher-order functions like `foldl`!).

So at this point, having been informed about `$nfx$`, Qi first transforms it for use as a flow. To do this, it rewrites the `$nfx$` expression by [adding a wrapping lambda](https://github.com/drym-org/qi/blob/3f63f9ce77231dffec14cbd7ab7d063899d9e988/qi-lib/macro.rkt#L90) taking a single `v` argument that is then passed to the original macro --- basically just wrapping the macro so it can be used as a function.

And finally, expansion is now delegated to the inner `$nfx$` macro. But of course, at this stage, the expression has already been rewritten in a way that can't then be parsed correctly by the `$nfx$` macro. That is,

```scheme
($nfx$ string-split ~> rest ...)

```

has become:

```scheme
(lambda (v)
  ($nfx$ v string-split ~> rest ~> ...))

```

… as you observed!

The issue is that, unlike `and`, but more like `let`, `$nfx$` is a Racket macro that _doesn't_ have the same syntax as function application and doesn't behave like a function. So it can't be treated as a [_flow_](https://docs.racket-lang.org/qi/Principles_of_Qi.html#%28part._.What_is_a_.Flow_%29) by using `define-qi-foreign-syntaxes`.

Regarding a solution, one option is to wrap the inner infix expression with [`(esc ...)`](https://docs.racket-lang.org/qi/Qi_Forms.html#%28form._%28%28lib._qi%2Fmain..rkt%29._esc%29%29). This tells Qi that what follows is a Racket expression, and so it will not attempt to expand it.

Another way could be to write a `$nfx$` [_Qi_ macro](https://docs.racket-lang.org/qi/Qi_Macros.html) using `define-qi-syntax-rule`, which expands to an appropriate use of the `$nfx$` _Racket_ macro, so that, in a way, at the point where Qi is about to rewrite the `$nfx$` macro, you get to take back control of expansion at that point. In fact, the previous solution is also similar, where instead of taking control back yourself, you give control to Racket, which is good because `$nfx$` is a _Racket_ macro, after all.

Possibly one simple way to write this Qi macro is just:

```scheme
(define-qi-syntax-rule ($nfx$ e ...)
  (esc ($nfx$ e ...)))

```

I suspect this will work precisely because the `$nfx$` was inserted at the reading stage in a _context-free_ way, so that it doesn't refer to a specific binding (e.g., the Racket macro `$nfx$`), and the same `$nfx$` syntax could refer to either the Qi macro or the Racket macro when the bindings are resolved at expansion time. I could be wrong, though!

If this approach works out, then it could be worth making an adapter library for curly infix syntax and Qi, which defines the necessary adapter macros like `$nfx$` as Qi macros.

If you have any other ideas or thoughts (or if we need to debug further), you're welcome to stop by at the next (or any) Qi meetup, which [happens on Fridays](https://racket.discourse.group/t/racket-events-calendar/2173) 🙂

---

_[View the full topic](https://racket.discourse.group/t/apply-values-to-a-procedure/3506)._
