Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A "do it now or do it later" macro #304

Closed
masak opened this issue Jun 4, 2018 · 5 comments
Closed

A "do it now or do it later" macro #304

masak opened this issue Jun 4, 2018 · 5 comments

Comments

@masak
Copy link
Owner

masak commented Jun 4, 2018

Thinking about the format macro.

We already have a ticket #183 to improve the macro using the (emerging) built-in macro system. But I just thought of another thing.

Looking at how the macro is used at the end of the file:

say( format("{0}{1}{0}", ["abra", "cad"]) );        # abracadabra
say( format("foo{0}bar", ["{1}"]) );                # foo{1}bar ({} things can occur in the arguments)

Those are all constant strings and arrays of strings going into the macro. If it could only detect that somehow, and run the quasi code at macro invocation time, it could return (a Qtree of) the constant result.

What would the code doing that computation look like? Why, it'd be the quasi, but without the quasi:

return replaceAll(fmt, sub transform(arg) {
    return args[+arg];
});

(Here assuming fmt contains the format string (not its Qtree) and args contains the array of format arguments.)

That code is much easier to read, too. No unquotes.

Because we don't like writing duplicated code, the above "direct" code ought to be able to run either directly at macro time, when possible, or "inject itself" as the current quasi implementation does and run at runtime, when necessary.

I'm not firing at 100% right now, but I think this macro streamline could do that:

return streamline(quasi {
    replaceAll({{{fmt}}}, sub transform(arg) {
        return {{{args}}}[+arg];
    });
});

All it'd need to do was to recognize that the unquotes it just filled in were constant/literal values, and so it has enough to run the results of the quasi now, right here in the macro; it runs them, gets a string back, and turns that back into a Qtree. Maybe?

Streamline would need to intercept the normal quasi/unquote templating process in order to check all the unquotes. So it's definitely a macro. But can it do that? We just said that a quasi is not a Qtree fragment, it's a function, which indicates it's to some extent opaque. But... I don't think it's unreasonable to still expose (Qtree fragments for) the code in the unquotes. Those evaluate in the context of the macro, not the quasi, after all. They're more like arguments to the quasi than an actual part of it.

So, I think it all works out. In fact, I'm glad I thought of this use case, because it shows a bit more what we expect of Q::Term::Quasi also; in this case we expect to be able to iterate over the unquotes so that we can get at their contents and evaluate them.

Here's to more macros for macro authors! 🍺

@vendethiel
Copy link
Collaborator

Even better: since the format string is known, you can optimize it even if not all other arguments are known :).

@masak
Copy link
Owner Author

masak commented Jun 5, 2018

Huh! Yes — fmt is in some sense more "stable" or long-lived than args. Maybe there's some way to formulate this pattern so that we can separately streamline them, getting either of the following three situations:

  • fmt and args both dynamic
  • fmt constant, args dynamic
  • fmt and args both constant

@masak
Copy link
Owner Author

masak commented Jun 12, 2018

Wondering whether annotations might not capture this better, either on the macro parameters or on the macro itself. Fuzzy on the details.

@masak
Copy link
Owner Author

masak commented Jun 17, 2018

Suddenly I'm thinking that this might be much better handled by the compiler itself. Maybe we're needlessly adding hints to the compiler here, like register in C?

@masak
Copy link
Owner Author

masak commented Jun 18, 2018

...Yep.

Going to close this one, as I suspect it'll get stuck between a "we have more interesting low-hanging fruit to pick" rock and an "a sufficiently savvy compiler should be able to already do this without a hint" hard place.

Still an interesting/worthwhile idea, though, AFAICS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants