Is there a good description for how to define lambda lists with keyword arguments in clojure? Does the concept exist? I know about (fn [x & others] ...) But what about keyword arguments?
It’s in the destructuring segment of the documentation since these binding forms work for any binding, not just lambdas https://clojure.org/guides/destructuring#_associative_destructuring
You can pass them either as & args or as a map.
Go with whichever you find more readable unless you care about performance. Then prefer the map form.
Great, and it seems the bizarre feature I was hoping for actually works.
The default values are allowed to reference each other in the same way that it works in Common Lisp
In this example debug defaults to the value of val and verbose defaults to the value of debug. Even if I call the function with :verbose or with :debug
How can I make a recursive call to a function like configure passing the exact same keys as I already have, and how can I make a recursive call to configure but overriding some of the keys?
Or some other contrived example.
That way opts is easy to carry around and/or modify as you see fit in your recursion, just assoc other values into it if you want to modify it.
I hope that answers your question.
Sorry bsless, did you omit the & intentionally to indicate that you’d rather make the assoc list a required argument. I just want to understand your intent.
if you want to enforce default opts for variadic args. I don’t know if CL supports this.
I mainly omitted it because it makes the recursion annoying because you’ll have to write all of the arguments explicitly, even if you don’t change them, while if it’s a map you can just pass it unchanged.
bsless, the reason I’m asking in the first place is because I actually did implement the function in my application as two required arguments, the second of which is as assoc list. But I’m translating this from a CL application which uses &rest and &key arguments.
My application seems to work, but it occurs to me that my manipulation of the assoc list when I call the function seems like I’m doing with that the language could be doing for me.
opts is a hash map in configure but when you use apply, seq is applied to the hash map which produces a sequence of pairs (of key/value) which is not the same as passing those arguments in the first place.
This is why this style of function is discouraged except for strictly “user-level” where a human types the function calls directly. It’s why passing arguments as a single hash map is generally preferred, even for “user-level” code – i.e., without the & – and then you can simply call the function recursively passing the hash map directly (without apply).
If you really still want to use the & form, you can invoke the recursive call with apply if you flatten out the hash map:
Just a warning, it is not safe to do :or {debug val, verbose debug} as you’re doing here. Maps are inherently unordered and there is no guarantee provided that debug will be bound before verbose's value is evaluated. If you need to do this, you should provide an inner let that establishes debug and verbose that can rely on let's ordering guarantees.
You may also want to be a little suspicious about having the :or rely on val being bound already, although that is definitely true of the current implementation, and unlikely that that assumption would be violated in the future.
In general, I think it’s safest to make :or defaults only constant values, and leave anything trickier for a let that can ensure the ordering of evaluation.