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

Add a macro for punning keyword arguments #1686

Closed
wants to merge 1 commit into from

Conversation

Kodiologist
Copy link
Member

Closes #1119.

Replaces #1685.

@gilch
Copy link
Member

gilch commented Oct 9, 2018

Putting this in core seems premature. It's an experimental macro not even based on anything from Clojure or Common Lisp, that means it belongs in contrib. I don't imagine I'd use this enough to justify it, but if it proves popular we could then move it to extra.

(HyExpression (reduce + (gfor x body
(if (and (keyword? x) (.startswith x.name "^"))
[(HyKeyword (cut x.name 1)) (HySymbol (cut x.name 1))]
[x])))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This definition isn't indented properly. Make sure it passes parlinter.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked you to stop this. Twice. Then you insulted me about it. Please don't comment on my indentation again.

@Kodiologist
Copy link
Member Author

I wouldn't say it's experimental (it's a very simple macro), and the inclusion criteria for contrib and extra have nothing to do with Common Lisp or Clojure.

@brandonwillard
Copy link
Member

What's the inclusion criteria for hy.core.macros?

@Kodiologist
Copy link
Member Author

We never decided on any. In practice, it contains macros that are short and are of general use, and we should probably stick to that.

@Kodiologist
Copy link
Member Author

@gilch To be clear, are you vetoing this as-is?

@gilch
Copy link
Member

gilch commented Oct 12, 2018

Yes, vetoed.

I wouldn't say it's experimental

I sure would! By "experimental" I don't mean only to say that we're not sure if it meets the intended spec, but also that we're not sure if the spec is even what we want.

There should be one-- and preferably only one --obvious way to do it.

The above is a good argument for standardizing general-use functions and macros so obvious that they get invented independently anyway, but in slightly incompatible ways. (Like attach, probably hylang/hyrule#35.) Those should be in Hy's standard library. And of those, if they get used very frequently, that's an argument to put it in core. Hy doesn't have as many lines of code as older Lisps, but it needs a standard library for that to happen. It's a chicken/egg problem. We can bootstrap that problem by including Python's standard library for the basic functions, but that doesn't give us any macros. Where are we supposed to get those?

From Clojure's core. (And from its core syntax and special forms where Hy is lacking, like let and #%--formerly known as xi.) Hy has always borrowed heavily from Clojure. Clojure was designed by careful thinkers (mostly Rich) with the benefit of hindsight from decades of prior Lisp experience. Maybe also from Common Lisp where they make sense--it unified a lot of older dialects. It has some warts, but even with decades of experience later, the Lisp community mostly agrees that the design committee did a good job.

So far, pun doesn't meet the above criteria. It's not in Clojure. It's not in Common Lisp. It's not in any Lisp I've heard of. It wasn't independently invented by multiple Hypsters. It's not addressing a problem I've come across enough for me to even think I want it.

I'm uncomfortable with the whole approach. Are we sure we want a macro rather than a tag? Yes, a macro is loads better than a compiler extension. But Hy's keyword arguments are already allowed to start with ^. Maybe you have to call (spam :foo foo :bar bar :^q 42) Sounds like a job for pun. (pun spam :^foo :^bar :^q 42) Uh, oh! The 42 is now a positional argument. Runtime error, if you're lucky. Subtle bug, if you're not. How do we work around it? Maybe (pun spam :^foo :^bar #** {'^q 42})? If we're using #** anyway, maybe vars-of #1119 was a better approach. Maybe we can make the macro smarter? But what if we really did want a positional argument there? Maybe (pun spam :^foo :^bar :XhatXq q) oh, but you've vetoed those mangle improvements #1651. It would have to be :_hyx_Xcircumflex_accentXq. pun made it worse. Maybe it doesn't come up enough to be a problem in practice? You certainly don't get parameter names starting with ^ in Python libraries. That's not allowed in Python identifiers. I don't know how well this would work in practice. And, emphatically, neither do you.

That's why it's experimental.

None of this is enough to keep it out of contrib, by the way, with our other experiments. Maybe the broader Hy community will eventually gain enough experience with it to justify promoting it to core. Eventually. Perhaps with changes, though.

@Kodiologist
Copy link
Member Author

It's clear that lots of time and people and thinking went into previous languages, but none of those things imply that the results are any good. People's decisions are subject to inertia and groupthink, and there's no group so large that anything important is guaranteed to be thought of by somebody in the group. How things have been done previously is not any indiciation as to what should be done.

Are we sure we want a macro rather than a tag?

The distinction doesn't seem important. I could switch it to a tag macro if you'd prefer that.

How do we work around it?

With mangling, as you just realized and as already tested. It's clumsy, but it's hard to see how the clumsiness will matter considering the sheer weirdness of beginning a function parameter's name with a caret, and the coincidence of wanting to use pun in the same call.

Maybe (pun spam :^foo :^bar :XhatXq q) oh, but you've vetoed those mangle improvements #1651

To be clear, I'm not against mangling nicknames for ASCII characters, just the absence of a clear marker of whether a name has been mangled (which is currently the hyx_ prefix).

I don't know how well this would work in practice. And, emphatically, neither do you.

I'd anticipated this problem you thought of, but if you can think of any other potential problems with the macro, by all means mention them and I can fix them and add tests. It's appropriate to hold up a PR for known problems, but not for problems they might have but we haven't even thought of yet.

@Kodiologist
Copy link
Member Author

@gilch Have you thought of any potential problems?

@Kodiologist
Copy link
Member Author

@gilch So what's the word? Do you want it as a tag macro instead?

@Kodiologist Kodiologist deleted the punning branch January 20, 2019 14:32
@Kodiologist Kodiologist restored the punning branch January 20, 2019 14:45
@Kodiologist Kodiologist reopened this Jan 20, 2019
@alphapapa
Copy link
Contributor

Although I've known of Hy for a while, I haven't used it "in anger" much, so I'm still a tyro. My perspective comes from using other Lisps, so for whatever it's worth:

Since apply was removed (which I miss, but can adapt to), the proposed syntax seems strange to me, since it would work roughly like apply:

(apply dict [:monitor monitor :verbose verbose :cv-folds cv-folds])
(pun dict :^monitor :^verbose :^cv-folds)

What if pun worked like the replacement for apply, i.e. using #**, something like:

(dict #** (pun monitor verbose cv-folds))

@Kodiologist
Copy link
Member Author

In that case, (pun monitor verbose cv-folds) would presumably mean (dict :monitor monitor :verbose verbose :cv-folds cv-folds), so the leading dict #** isn't necessary. But for calling any other function, it's just extra characters.

Can I ask why you find yourself missing apply? There should no advantage to it over #* and #**.

@alphapapa
Copy link
Contributor

alphapapa commented Oct 30, 2019

In that case, (pun monitor verbose cv-folds) would presumably mean (dict :monitor monitor :verbose verbose :cv-folds cv-folds), so the leading dict #** isn't necessary. But for calling any other function, it's just extra characters.

Right, it is more characters, but it would follow what seems to now be the encouraged pattern of using #* and #**. The (pun fn...) syntax feels like going back to apply. (Maybe I'm wrong and that's not the encouraged pattern now; this is just my impression as a user watching from outside.)

Can I ask why you find yourself missing apply? There should no advantage to it over #* and #**.

Because I use apply in other Lisps, so not being able to use it in Hy means more mental effort when switching to Hy mode. Every Lispy pattern I can't use in Hy makes the transition a little harder. :)

@Kodiologist Kodiologist closed this Jan 5, 2020
@Kodiologist Kodiologist deleted the punning branch January 5, 2020 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[feature] Shorthand for :kwarg True, :kwarg False, and :kwarg kwarg
4 participants