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

Document &keys better. #205

Closed
amano-kenji opened this issue Jan 20, 2024 · 12 comments
Closed

Document &keys better. #205

amano-kenji opened this issue Jan 20, 2024 · 12 comments

Comments

@amano-kenji
Copy link

amano-kenji commented Jan 20, 2024

Until recently, I didn't recognize the example for &keys on https://janet-lang.org/docs/functions.html was using destructuring. I thought the destructured struct was the only allowed syntax for &keys.

I didn't think it was a destructured struct. I thought it was just the only syntax for &keys.

(defn test
  [&keys {:argument1 arg1 :argument2 arg2}]
  (print arg1)
  (print arg2))

For years, I didn't know something like this was possible.

(defn test
  [&keys struct]
  (pp struct))

https://janet-lang.org/docs/functions.html should mention that what follows after &keys is actually a destructured struct.

@sogaiu
Copy link
Contributor

sogaiu commented Jan 20, 2024

Thanks for elaborating. Perhaps the text could expand on things a bit more. May be a PR would be accepted toward that end.

Note though that currently the following text exists at the bottom of the destructuring page:

Destructuring works in many places in Janet, including let expressions, function parameters, and var.

@amano-kenji
Copy link
Author

I didn't recognize that there was struct destructuring after &keys....
I thought it was a special syntax...

@CFiggers
Copy link
Contributor

CFiggers commented Jan 20, 2024

I thought the same thing!

I saw your original issue over in janet-lang/janet (agree that this is a better place for it). Before that I didn't realize that [&keys foo] was valid syntax.

This is a useful thing to know, because sometimes I need to pass the whole struct received after &keys to another function. But if I've destructured it in the main function's params, then there's no symbol bound to the whole struct and I have to manually reconstruct it in the arguments of the sub function:

(defn foo [&keys {:a apples :b bananas}]
  (print apples)
  (print bananas)
  (count-calories {:a apples :b bananas}))

This small example is already annoying, but it's much worse the more keys are in the struct.

That kinda turned me off from using &keys at all almost ever:

(defn foo [fruitmap]
  (print (fruitmap :a))
  (print (fruitmap :b))
  (count-calories fruitmap))

But it turns out, this is valid:

(defn foo [&keys fruitmap]
  (print (fruitmap :a))
  (print (fruitmap :b))
  (count-calories fruitmap))

So &keys might get more use in my Janet code moving forward.

What would be really nice is if I could have the best of both worlds:

(defn foo [&keys {:a apples :b bananas} :as fruitmap]
  (print apples)
  (print bananas)
  (count-calories fruitmap))

But I don't think Janet's defn/approach to destructuring in general currently supports this.

@sogaiu
Copy link
Contributor

sogaiu commented Jan 20, 2024

Yeah an :as sort of thing could be nice.

Not sure of the specifics though.

For reference, the fennel folks seem to do this sort of thing (inspired by Clojure perhaps?):

{:expr expr#
 :res result#
 :debugger-id ,(tostring debugger-id)
 :id id#
 &as data#}

Ignore the # and , stuff -- it's from within a macro definition (^^;

@pepe
Copy link
Member

pepe commented Jan 20, 2024

I see :as as Clojurism :-), as it brings another layer of magic into the restructuring. All the puns intended :-D.

@CFiggers
Copy link
Contributor

I'm sure if there was anything really bothering me I could find a way to fix it with macros, at least to my own satisfaction. 🙂 No need to change the language, unless more people than just me would find something of that kind useful.

More on the topic of this issue, I do think it would be helpful to clarify the docs around &keys syntax.

@sogaiu
Copy link
Contributor

sogaiu commented Jan 21, 2024

Not sure there is really a nice solution, but IIUC ATM there is a trade-off one must make between:

  • documenting keys using destructuring in the function signature
  • use of passed struct within the function body

I think you can't have your cake and eat it too...though may be this cake is not tasty enough (^^;


Back to the topic (as CFiggers mentioned), perhaps an additional example in the docs (plus some text) that demonstrates the point would be worthwhile.

@amano-kenji
Copy link
Author

Haskell provides an enhanced destructuring syntax.

For example, in haskell, something like this is possible

(defn
  [arg1 &keys attrs@{:abc abc :bcd bcd}]
  (pp attrs)
  (pp abc)
  ...)

@sogaiu
Copy link
Contributor

sogaiu commented Feb 4, 2024

Regarding possible changes to the documentation, perhaps an additional example can be added to the end of the keyword-style arguments section along with some explanatory text.

Here's a first draft:

Note that what follows `&keys` does not have to be a 
struct and can instead be a single symbol.  The
symbol can then be used as a name within the function
body for a struct containing the passed keys and values:

(defn feline-counter
  [&keys animals]
  (if-let [n-furries (get animals :cat)]
    (printf "Awww, there are %d cats!" n-furries)
    (print "Shucks, where are my friends?")))

(feline-counter :ant 1 :bee 2 :cat 3)

@amano-kenji
Copy link
Author

That's what I meant.

sogaiu pushed a commit to sogaiu/janet-lang.org that referenced this issue Feb 4, 2024
sogaiu pushed a commit to sogaiu/janet-lang.org that referenced this issue Feb 4, 2024
@sogaiu
Copy link
Contributor

sogaiu commented Feb 4, 2024

Thanks for clarifying.

I submitted PR #214.

bakpakin added a commit that referenced this issue Apr 15, 2024
@sogaiu
Copy link
Contributor

sogaiu commented Jun 7, 2024

Looks like this issue may have been address by the merging of #214. Perhaps it can be closed.

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

No branches or pull requests

4 participants