laurent.orseau
2021-3-7 13:22:28

Thanks for all the input @greg. Food for thought.


laurent.orseau
2021-3-7 13:23:15

maybe @robby has some opinion about this? (see top post)


robby
2021-3-7 13:25:57

I don’t have anything useful to add I don’t think. Greg is right as far as I can tell. (I wouldn’t have thought of suggesting a runtime test actually)


laurent.orseau
2021-3-7 13:27:17

The problem with the runtime check is that the macro will need to be expanded to its full length before checking which branch to take. This is slow but more importantly it can make the code significantly larger (since it’s for each function definition). One option I see is to expand based on a environment variable, but I’ve found this path to be rather annoying in the past.


robby
2021-3-7 13:28:33

At macro expansion time it hasn’t been yet decided if errortrace instrumentation will happen or not.


robby
2021-3-7 13:28:42

Errortrace happens later.


robby
2021-3-7 13:28:51

After expansion is all done.


laurent.orseau
2021-3-7 13:29:07

okay, then I think I won’t use that route :confused:


robby
2021-3-7 13:29:21

So I think you need to design a new api somehow.


laurent.orseau
2021-3-7 13:30:47

Greg suggests that the check for where to put the zos (compiled vs compiled/drracket) would also be a runtime check, do you confirm @robby?


robby
2021-3-7 13:31:38

It sounds like a bad idea to do that check.


robby
2021-3-7 13:32:27

I don’t think there are any promises you can rely on like that.


laurent.orseau
2021-3-7 13:38:27

Then maybe it’s possible to detect the value of the debugging radio button at compile time?


laurent.orseau
2021-3-7 13:39:11

(probably in the Preferences somewhere?)


robby
2021-3-7 13:39:42

I don’t think this is a good idea.


robby
2021-3-7 13:40:15

I’ll stick with my suggestion that you design a new API that captures exactly what you want via some documented predicate.


laurent.orseau
2021-3-7 13:41:20

But that puts the burden on the user :confused:


robby
2021-3-7 13:41:27

The. You can implement the predicate either in some tricky hacky way or not but you leave a path open for not having horrible backwards compatibility constraints.


robby
2021-3-7 13:41:52

I don’t see why.


robby
2021-3-7 13:42:29

You are designing and publishing an API that you can rely on instead of relying on things that are best left as internal details of drr


laurent.orseau
2021-3-7 13:43:23

But then the user has to know about this API and switch themselves something to turn on/off my debugging mode, when there’s already something like that happening in DrRacket


laurent.orseau
2021-3-7 13:44:27

But at least I can have an API to let the user choose what they want, plus a default automatic mode that uses the DrRacket debugging value maybe, and this can be deactivated


robby
2021-3-7 13:45:10

I don’t think so?


robby
2021-3-7 13:45:59

You design, implement, and document an API with a predicate that captures exactly what you want to capture. The documentation makes it clear when this function should return #t or what. So now we know what the predicate should do and we’ve divorced the meaning of the predicate form the state of various internals of DrRacket.


robby
2021-3-7 13:46:17

Then you implemetn the API today, perhaps using the internals of DrRacket or perhaps via a pull request to DrRacket.


robby
2021-3-7 13:46:21

Then you call the API.


robby
2021-3-7 13:46:29

I don’t see how there are any users involved here.


robby
2021-3-7 13:46:45

It is all about being clear about what this new predicate is supposed to mean


laurent.orseau
2021-3-7 13:47:10

The predicate means “more debugging info, but larger generated code”


robby
2021-3-7 13:47:12

Compare with the situation where you document that your macros depend on the value of the parameter that determines where zo files go and if it contains the word “drracket” in it.


robby
2021-3-7 13:47:34

As long as the predicate doesn’t mean “drracket’s internal state looks like X not Y” that seems like an improvement to me.


robby
2021-3-7 13:48:03

I really would appreciate you not tying my hands if I want to fix bugs in drracket but am not able to because it breaks this thing you’re contemplating doing now.


laurent.orseau
2021-3-7 13:48:23

oh yeah, that does make a lot of sense :slightly_smiling_face:


laurent.orseau
2021-3-7 13:50:00

The burden that this could put on your shoulders completely skipped my mind I must say, sorry


robby
2021-3-7 13:50:06

I also think you probably have something slightly more refined and helpful than just what you quoted above. I guess that that’s the essence of it, but some examples of how it might be useful, etc., will go a long way in the API docs.


robby
2021-3-7 13:50:22

Oh, it’s okay!


robby
2021-3-7 13:52:40

I also think that some api docs with some examsples and whatnot plus a request for others comments might go a long way too.


robby
2021-3-7 13:53:03

Once people can see clearly what you have in mind, some good suggestions might be forthcoming.


laurent.orseau
2021-3-7 14:00:37

Basically I’m writing a variant of define that can do compile-time error checking on arguments (so syntax-check plays an essential role in this):


laurent.orseau
2021-3-7 14:01:45

But this requires define to have a significantly larger expanded code.


laurent.orseau
2021-3-7 14:03:09

it would still be useful also with raco make , so you’re definitely right that I shouldn’t tie it to a drr value in any case.


robby
2021-3-7 14:03:57

What happens if you write (define x (if (read) foo goo)) where one of them has a keyword and the other doesnt?


laurent.orseau
2021-3-7 14:03:59

But once everything compiles, the error checking expanded code is useless and should be thrown away


sorawee
2021-3-7 14:04:06

@mflatt is it feasible to get (for ([x xs]) ...) to be as efficient as (for ([x (in-list xs)]) ...) when cptypes can figure that xs is a list?


laurent.orseau
2021-3-7 14:04:34

The longer expansion is only in application position like (foo ...)


robby
2021-3-7 14:05:16

So this code should live only at compile time?


laurent.orseau
2021-3-7 14:05:20

yes


robby
2021-3-7 14:05:39

Then I don’t think you want to condition on the presence of errortrace.


mflatt
2021-3-7 14:05:52

Offhand, I don’t know how to make that work.


robby
2021-3-7 14:05:54

Just check always


laurent.orseau
2021-3-7 14:06:39

check what?


robby
2021-3-7 14:07:42

If the appropriate keywords are present.


laurent.orseau
2021-3-7 14:09:40

hm… right. Plus I think I can largely mitigate the issue with a syntax-class to reduce the expanded code. Will have to try though.


sorawee
2021-3-7 14:19:45

I haven’t fully read the whole thread, but for @robby’s comment:

> At macro expansion time it hasn’t been yet decided if errortrace instrumentation will happen or not. I think in a sense it does decide already: the macro expansion is invoked by expand-syntax here: https://github.com/racket/errortrace/blob/master/errortrace-lib/errortrace/stacktrace.rkt#L693. So if we parameterize some parameters over that expand-syntax, I think macros would be able to query for the information.


samth
2021-3-7 14:20:32

I think the answer is “yes, in principle, but it would be hard in Chez currently”. Right now, Typed Racket optimizes the former by replacing (make-sequence '(x) xs) with (values unsafe-car unsafe-cdr values ...). That’s effectively what you’d get from inlining make-sequence and then seeing that you need to inline :list-gen and removing all the other parts of make-sequence that are irrelevant. That doesn’t get you to unsafe-car etc, though, but just the pair tests should accomplish that already. However, that kind of type-influenced inlining (it’s a bad idea to inline make-sequence unless this works out) isn’t there in Chez right now, plus I don’t know if Chez-level inlining will ever do something for make-sequence because it’s in a different module.


robby
2021-3-7 14:21:13

I agree that we could set something up where a promise to invoke errortrace or not after expansion would be communicated.


samth
2021-3-7 14:21:22

Oh, I should also note that what Typed Racket does is sufficient — the results after cp0 are the same as for using in-list.


robby
2021-3-7 14:22:08

I was trying to say that errortrace works by processing fully expanded code.


robby
2021-3-7 14:22:47

But I do agree that, in practice we don’t seem to be saving fully expanded code and then either adding instrumentation or not.


robby
2021-3-7 14:23:05

We certainly could, however. (Unless something changes).


robby
2021-3-7 14:23:59

But maybe @laurent.orseau ’s plans don’t require us to constrain errortrace after all? Let’s see.


laurent.orseau
2021-3-7 14:25:05

I’d certainly prefer to avoid having to write any PR :slightly_smiling_face:


hectometrocuadrado
2021-3-7 16:46:32

The Racket Foreign Interface reference doesn’t completely explain how _cvector works.



hectometrocuadrado
2021-3-7 16:47:01

the mode argument is the same _ptr has?


mflatt
2021-3-7 16:55:50

Yes — same as _list, so that part is meant to be covered by “The longer form behaves similarly to the https://docs.racket-lang.org/foreign/foreign_procedures.html#%28form._%28%28lib._ffi%2Funsafe..rkt%29.__list%29%29\|_list and https://docs.racket-lang.org/foreign/foreign_procedures.html#%28form._%28%28lib._ffi%2Funsafe..rkt%29.__vector%29%29\|_vector custom type…“, but it could certainly be clearer.


hectometrocuadrado
2021-3-7 16:57:38

Thanks!


kellysmith12.21
2021-3-8 00:55:37

Does anyone have experience with the ideas and API in the paper, Macros for Domain-Specific Languages? I have a couple of questions about how to correctly use the API for my project.


sorawee
2021-3-8 03:06:12

A macro question: how do I write a macro bump such that the following program works as intended?

#lang racket (define x 1) (let () (bump x 2) (println x) ;=> 3 ) (println x) ;=> 1


sorawee
2021-3-8 03:08:34

The difficult part for me is referencing previous x while defining it at the same time. I thought of using (splicing-let ([previous-x x]) (define x (+ previous-x val))), but that obviously doesn’t actually work.


sorawee
2021-3-8 03:16:53

It’s OK to change (define x 1) to (define-syntax x ...), btw, as long as all print still gives the desired results.


sorawee
2021-3-8 03:53:44

OK, turns out that for my use case, I can do all of this at compile-time, so this works for me:

#lang racket (require syntax/parse/define) (define-syntax-parser bump [(_ x v) #`(define-syntax x (+ #,(syntax-local-value #'x) v))]) (define-syntax-parser query [(_ x) #`#,(syntax-local-value #'x)]) (define-syntax x 1) (let () (bump x 2) (query x)) ;=> 3 (query x) ;=> 1


notjack
2021-3-8 06:43:43

You could do this by trampolining using local expansion


notjack
2021-3-8 06:44:24

(define x 1) (bump-allowing-block (bump x 2) (println x)) (println x)


notjack
2021-3-8 06:45:13

You’d have to make bump-allowing-block use local-expand with bump in the stop list, to translate its body into this: (let () (let ([x (+ x 2)]) (println x)))


notjack
2021-3-8 06:47:31

This is what I did for my guarded-block and define/guard macros in rebellion’s internals. Ryan gave me the idea on the users list, see this thread https://groups.google.com/g/racket-users/c/H-EppBmQ7oU



sorawee
2021-3-8 07:04:24

Yeah, with bump-allowing-block that would be easily possible, but I’m restricted to (let () ...)


notjack
2021-3-8 07:05:55

drat :(


sorawee
2021-3-8 07:16:40

@notjack idea: support or/c flattening: (or/c (or/c a b) c) = (or/c a b c)


sorawee
2021-3-8 07:17:05

This occurs when your existing refactoring replaces symbols with or/c, but there’s another or/c outside.


notjack
2021-3-8 07:18:50

@sorawee and, or, and and/c are similar cases. Maybe a helper for defining rewrite rules for flattenable constructs?


sorawee
2021-3-8 07:19:22

yeah


sorawee
2021-3-8 07:19:42

And they are associative, even in presence of shortcircuiting