
It looks like the CS variant of DrRacket 7.4 has a code signing issue on Mac.

What’s the error?

I’m curious about the ~optional
clause in syntax-parse

I’m wondering how it works and didn’t find the docs especially helpful

I use assocs for config and data files pretty often. It’s a breeze to deal with in Racket. I recently had to make a reader/writer for similar files in pure C++, no boost. Did you know that C++ finally introduced a way to (properly) read and write quoted strings in… C++14(!!)?

we use it in a few spots already in Heresy, but @alexknauth wrote all that code so I am not really sure how to work with it, and I have a fairly simple thing that would be much easier to do if I could add optional macro args without having to just add a whole new branching clause for a single thing

There are a few examples: > (syntax-parse #'(m #:foo 2 a b c)
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
(attribute x)])
#<syntax:eval:57:0 2>
> (syntax-parse #'(m a b c)
[(_ (~optional (~seq #:foo x) #:defaults ([x #'#f])) y:id ...)
(attribute x)])
#<syntax:eval:58:0 #f>
It looks like the first pattern (~seq #:foo x) is used to match #’(m a b c) if it succeeds fine - otherwise the pattern variables from the #:default list are bound.

Ahh, so I need to give a #:defaults clause or it won’t work?

Apparently no, since the #:default is optional. But does it do without?

Okay, that’t the next example: > (syntax-parse #'(m a b c)
[(_ (~optional (~seq #:foo x)) y:id ...)
(attribute x)])
#f

It does not seem to.

but possibly I’m not using this right at all

In the first two cases (attribute x)
was a syntax object, in the third simply #f
.

I think maybe ~optional
is not what I even want here then, as it seems to be for head-patterns and I only want an optional single term here

@jarcane Can you use (~or (~seq x) (~seq))
?

I think my problem is I need to figure out how to check for its absence in the matching expansion pattern. I get this: name: attribute contains non-syntax value value: #f in: name

@soegaard2 yeah, that method seems to work, but it of course needs to handle if x is not there. ie. it’ll return either syntax or #f, depending on whether it matches or not

@jarcane You might be able to use ~?
(see the docs for syntax
for an example). If not, you can check whether a pattern variable is absent using attribute
: (attribute x)
is #f
if x
is absent (as in soegaard2’s examples above).

Another thing you can do is define a helper maybe-blah
splicing syntax class with two cases: either a blah or (~seq)
. Then you can use #:with
or #:attr
to define attributes for each case, and just use those attributes in the macro’s template.

@nma.arvydas.silanskas hah, thanks. Slack needs paren matching.

@jarcane can you give an example? with a concrete example one of us can show how to use either (1. ~optional
+ #:defaults
) or (2. ~optional
without defaults + ~?
) to solve the problem. In the mean time “Grammar-style” examples might be the best I can do: 1. pattern (~optional pat #:defaults ([attr-id expr]))
, template temp
referring to attr-id
2. pattern (~optional pat)
, template (~? temp1 temp2)
where temp1
refers to attr-id
and temp2
is the fallback that doesn’t

@alexknauth The basic gist is that I need to pass the name of described things to them at creation so they can remember it, so I’m trying to add an optional argument to the thing macro to take that name and then pass it. The simplest (broken) clause I have so far is this:
[(thing (~or (~seq name:expr) (~seq)) (field:id value:expr) ...)
#'(make-thing `([field
,(let ([field
(fn (ths)
(syntax-parameterize ([Self (make-rename-transformer #'ths)])
(def-field-id field ths) ...
value))])
field)]
...)
name)]

This obviously doesn’t work because I’m missing how to handle the result of an ~optional or ~or clause, presumably

So name
might not be “bound”, right? What do you want the second argument of make-thing
to be in case it’s not bound?

So if the name
is #false
when you don’t supply one, that could be:
pattern (~or (~seq name:expr) (~seq))
template (~? name #false)

or with more context:
pattern (thing (~or (~seq name:expr) (~seq)) stuff ...)
template (make-thing `(stuff …) (~? name #false))

It needs a symbol, so probably just 'thing
which is the usual default name

Ok, then (~? name 'thing)
I guess

And there’s also another way which uses ~optional
with #:defaults
, and not ~?
, which looks like:
pattern (~optional name:expr #:defaults ([name #' ' thing]))
template name

I did the former and it seems to work, but I do agree the later is probably less messy to read code wise.

I’ll play with both, but thank you so much.

Oh, another pitfall that I didn’t see until now!

(thing (field1 value1) (field2 value2) ...)

In that example, you have to be careful that (field1 value1)
isn’t accidentally interpreted as the name
expression

oh yup, at least the ~or based solution now breaks

if you don’t give the optional it confuses the first field name for an identifier and tries to evaluate it, presumably because it expanded wrong

both ones break, because as far as syntax-parse is concerned (field1 value1)
looks like a valid :expr

yah.

would it work to make name an :id
and then wrap it in quote in the template? Or will it still confuse the list for the single value?

That would work. It would be less expressive, because a user couldn’t say something like (make-thing (string->symbol (string-append "ahhh" "!")) (field1 value1))
anymore, but if you don’t intend for them to do that then making it an :id
in the pattern, and quoting it in the template is great

Yeah, I think it’s best to make clear it’s meant to be an identifier.

that would make it unambiguous, because the :id
and (field value)
patterns never overlap

how can I then safely quote the id in a way that I don’t trip over the “undefined: cannot reference an identifier before its definition”

never mind, figured it out, just had some bad code from earlier attempts

And that is the very last new feature I am doing for the next new Heresy version before the Racketfest talk. :wink:

I just the other day changed over from yaml to sexpressions

those projects are my private fun ones though, noone cares how I store config files there :wink:

https://developer.squareup.com/blog/making-openapi-swagger-bearable-with-your-own-dsl/ :point_up: this is “how I tricked my co-workers” into using Racket. If it’s of interest to anyone :wink:

I know I’m late to the party, but I’m reading Matthew’s “Composable and Compilable Macros - You Want It When?” paper, and really enjoying it: https://www.cs.utah.edu/plt/publications/macromod.pdf One of my pet peeves is missing dates on articles/papers. Any idea when this was published? I figure at least 2002 given the references.

Ah, ICFP 2002 - had to back up to the directory: https://www.cs.utah.edu/plt/publications/

17 years - have no other Schemes implemented a similar module & phase system?

R6RS modules are close, but there are some differences. https://www.cs.indiana.edu/~dyb/pubs/implicit-phasing.pdf

(There is a comparison on the last page)

R6RS modules are close because, I suspect, Matthew Flatt was an editor and deeply involved in the process.

And I viewed the whole process as an experiment in whether agreeing on a module system would make more Scheme portable. (I think it turned out not to be enough, even for a stronger notion of “agreeing” than perhaps applies to R6RS.)

@badkins FWIW, date and venue for ACM papers is bottom of the first page, left side for 2-column format.

mea culpa !

If require includes conflicting declarations, it’s specified that this is an error. How would you correct this?

prefix-in
, rename-in
, or the like

I use test submodules and contract-out
a lot, but module+
bypasses the contacts. So I’ve gotten into the habit of always adding this near the top of my files: (module+ test
(require (submod "..")))
…which causes the unit tests to exercise the module’s public contracts. Does anyone else do this?

I do.