bkovitz
2018-11-6 16:35:00

Is there an easy way, in a syntax-parse macro, to accumulate named elements of some body, like this?


notjack
2018-11-6 16:42:46

@bkovitz I think it depends on what you want to do with each variant


notjack
2018-11-6 16:43:01

lexi.lambda
2018-11-6 16:43:49

@bkovitz You can do that using ~alt, like this: #lang racket (require syntax/parse/define) (define-syntax-parser gather #:datum-literals [is-a archetype] [(_ {~alt (is-a ~! parent-expr:expr ...+) (archetype ~! archetype-expr:expr ...+)} ...) #'(hash 'is-a (list parent-expr ... ...) 'archetype (list archetype-expr ... ...))])


lexi.lambda
2018-11-6 16:44:04
> (gather
   (is-a 'number)
   (archetype 42)
   (is-a 'given)
   (archetype 'number 'target))
'#hash((archetype . (42 number target)) (is-a . (number given)))

bkovitz
2018-11-6 16:44:17

Each variant needs to be handled somewhat differently, but the main idea is to accumulate them all into a hash table for use elsewhere in the program. Most of the values in the hash table would be lambdas whose arguments are specified right after nodeclass.


bkovitz
2018-11-6 16:45:02

Hmmm! This looks good!


bkovitz
2018-11-6 16:46:44

I spent a while looking at that page and didn’t figure out how to put the parts together to make exactly this little “gather” test. So that’s what ~! is for.


lexi.lambda
2018-11-6 16:47:38

The ~! isn’t actually necessary there; it will just give you better error reporting.


lexi.lambda
2018-11-6 16:48:08

The example I demonstrated will do the same thing without the ~!s, but it will affect error messages produced by misuses of gather.


bkovitz
2018-11-6 16:49:05

Oh, OK. And does #:datum-literals make it so you don’t have to bind the literals somewhere else?


lexi.lambda
2018-11-6 16:51:31

Yes, but in this case, you should probably use #:literals; I was just being lazy.


bkovitz
2018-11-6 16:51:46

Ah, OK.


lexi.lambda
2018-11-6 16:51:57

#:datum-literals recognizes the literals by their symbolic name, just by doing a check like (eq? (syntax-e #'some-id) 'some-symbol).


lexi.lambda
2018-11-6 16:52:21

#:literals recognizes the literals by their binding, by doing a check like (free-identifier=? #'some-id #'another-id).


jerome.martin.dev
2018-11-6 16:52:28

I still don’t get the difference between them. Why would there be literals bound to something?


lexi.lambda
2018-11-6 16:52:45

The advantage of recognizing literals by their binding is that users can rename-in the literals, and the macro will do the right thing!


greg
2018-11-6 16:52:58

If you’re open to using a different surface syntax, you could consider not using literals and instead use keywords. Something like (nodeclass (target a) #:is-a number #:archetype n #:is-a given #:archetype number target). Partly a matter of taste, but also the matching is simpler, and you avoid needing to think about literals and bindings etc.


jerome.martin.dev
2018-11-6 16:52:59

oh, clever trick


lexi.lambda
2018-11-6 16:53:31

For example, you can rename-in else from racket/base and cond will still treat it like else. It also means that if a user shadows else with a local variable binding, they can use it inside of cond, and it won’t be treated like a keyword.


bkovitz
2018-11-6 16:53:48

@lexi.lambda So that’s why! That needs to go into the documentation. :slightly_smiling_face:


jerome.martin.dev
2018-11-6 16:53:50

@lexi.lambda that’s nice


jerome.martin.dev
2018-11-6 16:54:29

I never realized it was possible to do that


lexi.lambda
2018-11-6 16:54:43

Sometimes you really do want #:datum-literals, if there’s no ambiguity with expressions and if users would never want to rename the names, but in the case that you’re using a literal to distinguish between a keyword and an expression (like cond does with else), you should use the binding, not the symbolic value.


notjack
2018-11-6 16:55:04

doing it by binding also means drracket’s binding arrows recognize the literals


bkovitz
2018-11-6 16:55:06

When I tried making a little test like gather, I’d run into problems because parent-expr and archetype-expr would be undefined in an invocation without an is-a or archetype clause. Why does your gather predefine them (correctly!) to empty lists?


lexi.lambda
2018-11-6 16:55:41

The key is the ... after the {~alt } clause.


bkovitz
2018-11-6 16:56:06

Oh. Now I see.


lexi.lambda
2018-11-6 16:56:12

bkovitz
2018-11-6 16:56:16

Do the curly braces have special significance?


lexi.lambda
2018-11-6 16:56:27

No, I am just weird.


bkovitz
2018-11-6 16:56:58

Ah, OK. I still haven’t gone over the entire syntax-parse language; still learning all the various pieces…


lexi.lambda
2018-11-6 16:57:17

It’s really big! But you can learn it as you go, so you don’t have to learn it all at once.


lexi.lambda
2018-11-6 16:57:35

(I think I learned syntax/parse over the course of multiple years.)


jerome.martin.dev
2018-11-6 16:58:27

I can confirm I learn new things about syntax/parse pretty often


bkovitz
2018-11-6 16:58:53

OK, good. I’m glad to hear it can be learned incrementally. A valuable property of a programming language!


greg
2018-11-6 17:00:22

My fault for typing it too soon, and it scrolled by, but I want to suggest again that a “more Rackety” way of handling keywords is to use #:keywords. :slightly_smiling_face: Like, in hindsight, the else in cond probably should have been #:else.


lexi.lambda
2018-11-6 17:00:46

For a while, when I first found syntax-parse, I basically just used it as a slightly nicer pattern language for syntax-case. I used with-syntax forms in the body to create local pattern bindings… which, as it turns out, is totally unnecessary! You can just use syntax/parse #:with clauses! There’s a lot there to discover.


bkovitz
2018-11-6 17:00:49

Whew, this is good news that the ... after {~alt } predefines all the attributes with ellipses to '(). Is there a page that explains that—and whatever other handy predefinitions occur?


jerome.martin.dev
2018-11-6 17:01:31

I went through exactly the same experience :stuck_out_tongue:


bkovitz
2018-11-6 17:01:32

@greg Now looking up #:keywords


lexi.lambda
2018-11-6 17:01:44

It’s not so much that ... magically makes unspecified attributes the empty list as it is that (foo ...) defaults foo to '() if no foos are given.


lexi.lambda
2018-11-6 17:02:04

That is, a repetition with no elements is just an empty repetition.


jerome.martin.dev
2018-11-6 17:02:59

I recon there is an ongoing and everlasting war in the mailing list about whether keywords are Good™ or Bad™, and it cycles back every year or so.


greg
2018-11-6 17:03:08

@bkovitz If you prefer the surface syntax you have, that’s great, and everything @lexi.lambda explained is helpful for that and important to know in general.


greg
2018-11-6 17:03:26

I’m not saying your surface syntax “ought to be” “more Rackety”. That’s your choice.


bkovitz
2018-11-6 17:04:02

@lexi.lambda OK, good. That clarifies the “default” attribute values. I don’t have my original version anymore, but somehow I kept getting undefined attributes. Problem solved!


bkovitz
2018-11-6 17:04:38

@greg Do you know where #:keywords is documented?


greg
2018-11-6 17:05:30

I would probably use keywords like #:is-a because it’s simple to match on those, and you don’t need to worry about how they’re bound (they can’t be). Also, I would probably write a macro where #:is-a can only appear once, and takes zero or more elements. And then maybe write another macro that allows #:is-a to appear multiple times, with one element each — and that macro’s only job is to do the “gathering” and then call the more basic macro. I like to break things into steps like that.


lexi.lambda
2018-11-6 17:06:41

To clarify: I don’t think @greg was talking about a specific #:keywords option to anything, but rather just suggesting to use keywords instead of literal identifiers.



jerome.martin.dev
2018-11-6 17:07:11

@bkovitz keywords are basic elements in racket, except in macros, where they have to be “emulated” by using (~seq #:my-keyword value)


lexi.lambda
2018-11-6 17:07:57

I think @bkovitz knows what keywords are and just misinterpreted @greg’s suggestion as talking about a specific option to something named “#:keywords”.



bkovitz
2018-11-6 17:08:05

Interesting. I’d certainly prefer to go “more Rackety”, just on the general principle that it’s usually better to go with the grain of the language. The current working version of this only uses macros a little bit. It just assembles a bunch of structs, and you can even make the structs and bind them to identifiers outside of a farg-model-spec and incorporate them within a farg-model-spec. I like the readability and simplicity, but I’ll rethink it based on what you’re saying here.


greg
2018-11-6 17:08:42

I don’t mean to distract or overwhelm you with too many choices!


bkovitz
2018-11-6 17:09:00

@greg Ohh, so you’re saying that maybe farg-model-spec could be a plain ol’ function that takes keyword arguments rather than a macro?


notjack
2018-11-6 17:09:02

I find choosing between s-expressions and keyword options for small DSLs like that to usually be a matter of whether I’m dealing with a list of options or an actual tree structure


jerome.martin.dev
2018-11-6 17:09:49

I guess it’s a matter of style, yes


macocio
2018-11-6 17:10:04

Do you choose between s-exprs and kws though? You can freely mix them


bkovitz
2018-11-6 17:10:29

@lexi.lambda Oops, yes, that’s right. I had misinterpreted, and you straightened it out.


notjack
2018-11-6 17:10:52

specifically, when choosing between this:

(nodeclass (target n)
    (is-a 'number)
    (archetype n)
    (is-a 'given)
    (archetype 'number 'target))

or this:

(nodeclass (target n)
    #:is-a 'number
    #:archetype n
    #:is-a 'given
    #:archetype 'number 'target)

I usually choose to use keyword options for any clause type that doesn’t allow other nested clauses inside it


bkovitz
2018-11-6 17:11:29

@notjack Interesting. Indeed the elements here form a list, not a tree structure.


macocio
2018-11-6 17:11:32

You can also do #:is-a (number) or (#:is-a number) or whatever, @notjack


notjack
2018-11-6 17:12:21

I can :) but macro readability is important


macocio
2018-11-6 17:12:54

I agree. It’s context-dependent. What you want as a delimiter matters too.


notjack
2018-11-6 17:13:36

if I were to use s-expressions in your use case @bkovitz, I’d probably collapse multiple instances of the same clause type into a single clause:

(nodeclass (target n)
    (is-a 'number 'given)
    (archetype n ['number 'target]))

notjack
2018-11-6 17:15:52

also I’m not sure what semantics your nodeclasses have, but it looks odd to me that things like number and target are quoted - the macro seems to use them like bound names of some sort (like how struct uses the field names to determine accessors)


bkovitz
2018-11-6 17:16:25

@notjack Do you mean to write a macro that rewrites the original farg-model-spec so that there is only one instance of each clause, or to restrict the syntax so that each clause can be provided only once?


jerome.martin.dev
2018-11-6 17:17:31

I wonder about this, recently: Should I make my macros look like s-expressions so that they can be easily used without breaking the consistency of the code around them, or should I ensure that they look “macro-y”? For example, when I write html as s-expr, and I want to include a special element in the page, I’d like my macro to look exactly like if I was writing HTML s-expr, so that it doesn’t break the flow. (div ([class "row"]) (div ([class "col"]) (my-super-calendar #:min-date "yesterday" #:max-date "tomorrow")) (div ([class "col"]))) versus (div ([class "row"]) (div ([class "col"]) (my-super-calendar ([min-date "yesterday"] [max-date "tomorrow"])) (div ([class "col"])))


greg
2018-11-6 17:18:18

(What I mentioned above was — do both. Write the easy thing first. Then write the desired thing using the easy thing. :slightly_smiling_face: Here the easy thing is probably what @notjack is suggesting.)


notjack
2018-11-6 17:18:30

@bkovitz I would probably not disallow multiple uses of the same clause, but document for users that using multiple instances unnecessarily is not recommended so there isn’t unnecessary style deviation. And this is in a hypothetical world where I’m defining the nodeclass syntax, not you :)


bkovitz
2018-11-6 17:18:33

I also find it “wrong” that number and target are quoted. I’m hoping to remove that in this next version. It’s a little tricky because those refer to other nodeclasses, which might not be defined yet—and might not even be defined in the present spec. The present spec might need to be combined with another spec to get definitions. (For now, I’m just going with whatever is simplest to implement.)


macocio
2018-11-6 17:18:55

@jerome.martin.dev wouldn’t you anyway use ` and , in this case to make it clear where you invoke a macro?


macocio
2018-11-6 17:19:47

@bkovitz you can quote the identifiers inside the macro instead, if required


jerome.martin.dev
2018-11-6 17:19:57

@macocio That’s what I’m currently struggling with. Should I hide quoting/unquoting or keeping it obvious?


bkovitz
2018-11-6 17:20:07

@macocio Ah, that sounds like a good simple solution.


macocio
2018-11-6 17:20:42

@jerome.martin.dev I’d make it as simple and obvious as possible. See the macro in its own right basically. What’s the best interface without thinking of the context it’s used in?


notjack
2018-11-6 17:21:03

@jerome.martin.dev because html attributes are arbitrary key-value pairs so there’s no use to having a key like class be a bound identifier, I’d probably just use keywords for everything there:

(div #:class "row"
  (div #:class "col"
    (my-super-calendar
      #:min-date "yesterday"
      #:max-date "tomorrow"))
  (div #:class "col"))

macocio
2018-11-6 17:21:07

non-obvious -> obvious haha


notjack
2018-11-6 17:21:21

also that way I’d be able to make tags be plain functions


jerome.martin.dev
2018-11-6 17:21:50

@notjack Yeah, I’d like a syntax like that, but then I need to define every possible HTML entity as a macro :confused:


macocio
2018-11-6 17:22:22

Or you can create an interpreter and have it use a list of valid elems @jerome.martin.dev


macocio
2018-11-6 17:22:44

But there’s already a builtin sexpr->html thingy in the webserver library isnt there?


notjack
2018-11-6 17:22:57

@jerome.martin.dev how many are there? if it’s under a thousand, defining a macro that takes a list of html entity names and defines each one wouldn’t be infeasible


jerome.martin.dev
2018-11-6 17:24:07

yeah, right now the only thing in the webserver library is xexpr, which is plain s-expr HTML without keywords, but I’d like to add some kind of entity system like what we’re discussing here


macocio
2018-11-6 17:25:20

entity system? Can’t you add that in using ` and ,? or is that undesirable?


jerome.martin.dev
2018-11-6 17:26:10

I’d like to prevent people from having to quote and unquote every time they want a custom element in their HTML markup, so that is feels easy to extend HTML with your own “entities”


notjack
2018-11-6 17:26:25

hmmm


macocio
2018-11-6 17:26:28

Aha. Right


notjack
2018-11-6 17:26:40

if they were functions, that would be doable by them defining a function


macocio
2018-11-6 17:26:51

Tbh I prefer the xexpr route, makes it obvious due to coloring what’s plain HTML and where I generate/insert other stuff


notjack
2018-11-6 17:28:05
(define (my-super-calender #:min-date min-date-str #:max-date max-date-str)
  (section #:class "my-super-calendar"
    (p #:class "min-date-text" min-date-str)
    (p #:class "max-date-text" max-date-str)
    …))

bkovitz
2018-11-6 17:28:39

Thanks, all, for the info and suggestions! I and a fellow grad student are now about to start implementing the next version of this thing. :slightly_smiling_face:


jerome.martin.dev
2018-11-6 17:29:36

@notjack yeah, something like that, except I didn’t want to generate all the base elements myself and kept the xexpr stuff. I guess you’re right, I need a macro that generates all the p, div, body functions


macocio
2018-11-6 17:30:19

What if you invert the idea


macocio
2018-11-6 17:30:41

Turn unknown funcs into plain html tags. Turn known funcs (whose IDs are bound) into fncalls :stuck_out_tongue:


jerome.martin.dev
2018-11-6 17:30:59

oh, yeah, why not!


notjack
2018-11-6 17:31:06

D:


macocio
2018-11-6 17:31:08

(this is quite dangerous if u import a div func for some reason though and it all goes to hell lol)


jerome.martin.dev
2018-11-6 17:31:17

ahah


notjack
2018-11-6 17:31:20

the road to hell is paved with dynamic scope


macocio
2018-11-6 17:31:39

why not use parameterize too while we’re at it


macocio
2018-11-6 17:31:50

emacslisp here we go


jerome.martin.dev
2018-11-6 17:32:06

:skull:


jerome.martin.dev
2018-11-6 17:33:27

I’m starting to think quotes are fine, in the end xD


notjack
2018-11-6 17:33:29
(parameterize ([current-tag-resolver (lambda (ignored-tag) 'marquee)])
  (div
    (p "no matter how hard you try")
    (p "you will never be rid of the <marquee> tag")))

macocio
2018-11-6 17:34:24

@jerome.martin.dev reminds me, every racket programmer implements #lang no-parens and halfway through realizes how good parentheses are and abandons the project :stuck_out_tongue:


jerome.martin.dev
2018-11-6 17:34:36

ahah


jerome.martin.dev
2018-11-6 17:36:05

but I’d really like something like (div #:class "rainbow)" instead of the tiresome (div ([class "rainbow"]))


macocio
2018-11-6 17:37:06

Why not write a macro that rewrites it to the xexpr form?


macocio
2018-11-6 17:37:23

Considering you can’t have kw elements in xexpr/html anyway (afaik)


jerome.martin.dev
2018-11-6 17:38:30

maybe a reader ? x)


notjack
2018-11-6 17:39:19

I’d like it most because if they’re functions I can use fancy-app to do things like this:

> (map (div #:class "rainbow" _) (list (p "foo") (p "bar") (p "baz")))
(list
 (div #:class "rainbow" (p "foo"))
 (div #:class "rainbow" (p "bar"))
 (div #:class "rainbow" (p "baz")))

jerome.martin.dev
2018-11-6 17:40:16

right !


macocio
2018-11-6 17:41:17

If they’re funcs you’ll have to define each kw. Is there a set amount of kws and can some elems not have certain tags?


notjack
2018-11-6 17:41:32

you can make functions that accept arbitrary keywords


macocio
2018-11-6 17:41:36

:open_mouth:


macocio
2018-11-6 17:41:40

I didn’t know


notjack
2018-11-6 17:41:41

It’s kind of painful to do so with make-keyword-procedure though


notjack
2018-11-6 17:41:56

I wrote an arguments package that has a define/arguments form for making that easier


jerome.martin.dev
2018-11-6 17:41:56

my mind blew up a bit


macocio
2018-11-6 17:41:59

Well then, https://www.w3schools.com/TAGs/ into a macro to generate all these funcs



notjack
2018-11-6 17:42:30
> (define/arguments (keywords-product args)
    (for/product ([(k v) (in-hash (arguments-keyword args))])
      v))
> (keywords-product #:foo 2 #:bar 3)
6
> (keywords-product 'ignored #:baz 6 #:blah 4)
24

notjack
2018-11-6 17:43:39

the package defines an arguments? type that’s just a bag of positional and keyword arguments:

> (arguments 1 2 3 #:foo "bar")
(arguments 1 2 3 #:foo "bar")

notjack
2018-11-6 17:44:21

(define/arguments (id args-id) body ...) is like define but for a procedure that accepts any arguments, collects them into an arguments? structure, and binds args-id to the collected arguments


jerome.martin.dev
2018-11-6 17:44:34

that looks perfect


notjack
2018-11-6 17:45:28

I’m happy you think so :D


jerome.martin.dev
2018-11-6 17:45:34

gotta use that :smile:


jerome.martin.dev
2018-11-6 17:45:59

I’ll make some kind of third-party library for HTML, then maybe we could add it to web-server


jerome.martin.dev
2018-11-6 17:49:40

Thanks for all the insights! See you around!


macocio
2018-11-6 17:50:40

Gettomg errortrace...: how do i make it print everythnig?


macocio
2018-11-6 17:50:46

getting*


notjack
2018-11-6 17:51:52

@macocio are you using drracket or is that output in a terminal?


macocio
2018-11-6 17:52:09

terminal


notjack
2018-11-6 17:53:05

Don’t know in general then. Is the error happening inside a rackunit test?


macocio
2018-11-6 17:53:13

Yeah


macocio
2018-11-6 17:53:25

I remember some truncation value for errors or something


macocio
2018-11-6 17:53:29

but it’s so hard to find in the docs


notjack
2018-11-6 17:54:11

I think rackunit has a bug related to this, let me check the github issues


notjack
2018-11-6 17:54:54

macocio
2018-11-6 17:58:01

#lang errortrace racket works better


macocio
2018-11-6 17:58:12

but then you need to add it to the file when doing raco test


notjack
2018-11-6 18:00:20

yeah, to be 100% clear - this is a bug and you shouldn’t have to add anything to get proper stacktraces from a rackunit test failure


notjack
2018-11-6 18:00:50

but until that gets fixed, #lang errortrace racket is a workaround


bkovitz
2018-11-6 18:01:22

When I try defining the ~alt as a syntax class, the compiler doesn’t like it. Any idea why this works inside define-syntax-parser but not in define-syntax-class?


notjack
2018-11-6 18:01:51

You need a ... after the (~alt option ...) clause


notjack
2018-11-6 18:01:56

(I think)


notjack
2018-11-6 18:02:46
(define-syntax-class nodeclass-elem
    #:datum-literals [is-a archetype]
    (pattern (~alt (is-a ~! parent-expr:expr ...+)
                   (archetype ~! archetype-expr:expr ...+)
             ...)))

bkovitz
2018-11-6 18:02:48

Indeed the original had ... there. So, it’s not possible to make a syntax class to match any nodeclass-elem?


notjack
2018-11-6 18:03:17

You can still make a syntax class to match a single nodeclass-elem, but you can’t reuse that class with ~alt


notjack
2018-11-6 18:03:25

as far as I know


lexi.lambda
2018-11-6 18:03:28

You need to make it a splicing syntax class, then do {~seq {~alt } ...}.


notjack
2018-11-6 18:03:59

oh I misread that you’re doing this in a syntax class and not a use of syntax parse


notjack
2018-11-6 18:04:00

oops


bkovitz
2018-11-6 18:04:07

So that’s what ~seq does!! I’d been wondering what was the difference from just matching the body of the ~seq.


lexi.lambda
2018-11-6 18:04:07

The idea is that a syntax class always matches a single term, but a sequence of alternatives must match multiple terms.


lexi.lambda
2018-11-6 18:04:20

A splicing syntax class allows you to match a sequence of terms.


bkovitz
2018-11-6 18:05:12

Thanks! That clarifies a lot. This is where we got stuck yesterday with attributes that didn’t “bubble up” to the top-level matching expression.


lexi.lambda
2018-11-6 18:06:19

~seq is essentially a pattern splicing form, and it can be used in a few different ways. One of the main uses is this one, when writing a splicing syntax class. Another is when you want to match pairs of arguments, a la arguments to the hash function, which you can do by writing {~seq a b} ....


bkovitz
2018-11-6 18:08:58

Hmm, this ~seq around ~alt with ... still gets an error:


bkovitz
2018-11-6 18:09:56

@lexi.lambda These explanations of the main uses of the various library functions/transformers are very helpful.


lexi.lambda
2018-11-6 18:10:16

You need define-splicing-syntax-class to make the syntax class splicing.


bkovitz
2018-11-6 18:10:22

Ah.


notjack
2018-11-6 18:10:28

@bkovitz other miscellaneous tips: I’ve gotten into the habit of always using the #:attributes option with define-syntax-class / define-splicing-syntax-class to make it explicit what attributes I need each variant to bind (and what attributes users of the class can access), and I’ve found that very helpful for reading syntax class definitions. You might also want to use the #:description option to 1) have a snippet of in-source docs on the purpose of the class and 2) improve error messages

(define-syntax-class binding-pair
  #:description "a pair of an identifier to bind and a right-hand-side expression"
  #:attributes [id expr]
  (pattern [id:id expr:expr]))

bkovitz
2018-11-6 18:12:40

@lexi.lambda That worked. The top-level code can even access the accumulated is-as and archetypes (with three ellipses!).


lexi.lambda
2018-11-6 18:14:07

You probably want to set it up so that you only need two ellipses, not three. Make sure that you don’t put an extra ellipsis after the use of the nodeclass-elem syntax class, since the ellipsis is already inside the class.


bkovitz
2018-11-6 18:14:08

@notjack I definitely like explicitness. We ran into troubles yesterday with #:attributes. I’ll try it right now with splicing.


notjack
2018-11-6 18:15:20

@bkovitz note that when using #:attributes with ellipses you have to specify in the #:attributes clause the number of ellipses each attribute is used with (unless it’s zero, which is the default)


notjack
2018-11-6 18:16:05

e.g. #:attributes [(parent-expr 1) (archetype-expr 2) some-other-attribute-which-needs-no-ellipses]


bkovitz
2018-11-6 18:17:15

@lexi.lambda OK, now I think I see: the splicing syntax class doesn’t match one nodeclass-elem, it matches a sequence of them (hence ~seq). It sounds like matching a sequence of alternatives in a single pattern goes with the grain of the language, and the approach we tried yesterday, defining a syntax class for a single nodeclass-elem is just the wrong approach.


bkovitz
2018-11-6 18:17:43

Ah, so the syntax-class should be named nodeclass-elems, not nodeclass-elem.


lexi.lambda
2018-11-6 18:18:41

Yes, you can think of {~alt } ... as really being one unit, along with any uses of ~optional, ~once, or ~between nested immediately inside the ~alt form. That is sort of a mini-language inside syntax/parse, which is itself a mini-language!


bkovitz
2018-11-6 18:19:37

OK, that clarifies yet more: {~alt } ... is really one unit, not to be broken apart across syntax patterns.


bkovitz
2018-11-6 18:20:11

Now down to two ellipses—which seems like conceptually the right number.


bkovitz
2018-11-6 18:23:27

@notjack Just added #:attributes. Yes, this helps readability: now it’s clear that we’re accumulating (in effect) lists of lists, since the number of ellipses is 2.


soegaard2
2018-11-6 21:18:10

@jerome.martin.dev An alternative is to use at-expressions (@-expressions) to write html. Example: https://github.com/soegaard/urlang/blob/master/urlang-examples/parabola/parabola.rkt#L118


bkovitz
2018-11-7 02:18:00

Does anyone know how to make an sxpath search function that searches for an arbitrary string? It appears to treat some characters specially, and I haven’t yet found an escape character.