is it possible to access the result of a test in a cond in it's corresponding branch?
(cond ...
(some-test? args) test-result
...)the test should only execute once the above tests have failed and if this test passes I don't want anything after it to compute hence I chose to use a cond
so basically is there a cond-let or something similar to if-let that we have
the only approach I can think of is memoising the some-test? but if some better cleaner approach is doable then I'd prefer that
Nested if-lets
yeah this is what I'm doing at the moment
I guess that's the only approach...
You can make your own macro, or use a utility lib
https://github.com/tonsky/clojure-plus?tab=readme-ov-file#cond
will check it out, thanks!
although for now memoise is a good enough hack
Multiple ways to handle it, with a custom macro being somewhere at the very bottom of the list. :) Memoize is also not great as it's just unnecessary complexity.
E.g. when you need something like
(if-let [x (get-x args)]
(process-x x)
(if-let [y (get-y args)]
(process-y y)
...))
it might be possible to replace it wit
(or (some-> (get-x args) (process-x))
(some-> (get-y args) (process-y)))
interesting, although correct me if I'm wrong in the first case both process-* functions can execute OR only the process-x but in the other impl (using the or and some->) it is possible for either to execute but never both, correct?
although the some-> function does solve another issue I was having, wherein I wanted to run a series of steps based on results of the previous one, so thanks for the indirect assist xD
In the first case, how would process-y be executed when process-x has already been executed?
They're in different branches of the same if.
ah my bad, I switched to indentation block semantics in my head 😳
> is it possible to access the result of a test in a cond in it's corresponding branch?
this is what condp is for
well - maybe not a perfect fit here, but often this can be squeezed into the shape condp needs with the right pred arg
eg (example from docs website)
(condp some [1 2 3 4]
#{0 6 7} :>> inc
#{4 5 9} :>> dec
#{1 2 3} :>> #(+ % 3))The :>> is new will check out, thanks!
condp might be a bad fit here as it uses the same comparison function at each step
but its behavior reminded me of what you wanted, it might match your use case if you massage it right
not in this case, but definitely good to know
I don't think there's anything wrong with using a macro if it makes the code clearer. There are lots of different takes on cond-let in the wild, https://cloogle.phronemophobic.com/name-search.html?q=cond-let&tables=var-definitions.
Rather than memoize, I've used delay. You can set up all the variables in a regular let statement and only calculate necessary results. It's ok, but not great.
Regarding macros, quoting hiredman. :D https://clojurians.slack.com/archives/C053AK3F9/p1747276940117959?thread_ts=1746958763.518749&cid=C053AK3F9 I'm fortunate enough to only rarely stumble upon usages of such macros. And in what feels like 90% of the time, they're used very few times in the whole project, sometimes just once. Which makes the cognitive load ratio completely not in favor of them.
what are currently some of the most popular libraries for writing web APIs in clojure?
I use https://cljdoc.org/d/metosin/reitit/0.9.0/doc/introduction which supports ring and provides OpenAPI docs. The routing is defined as a data structure. Reitit is also used by projects like https://kit-clj.github.io/
Ring is the most popular library I'd say. A web API can be implemented with any Ring compliant server like ring-jetty (the default for ring) or http-kit. Then you just set it up to accept and return content-type json and you got yourself a basic web API
The second most popular after that is Pedestal probably: https://github.com/pedestal/pedestal
thank you all for the suggestions, I'll be looking into these!
can the fspec spec be used for runtime validation, or is it only used when enabled with the spec instrumentation tools? I'm asking because trying to do (valid? myfspec myfunc) attempts to call generators
How else would it tell if a function is valid?
I thought that maybe there could be a wrapper that automatically adds :pre and :post conditions to a function call, or something of the sort, by using the spec declaration
But valid? returns true or false right away
How would it know if those pre/posts are triggered?
is it a macro?
Even if it was, how could it immediately return true or false by instrumenting the function?
well 'immediately' is ambiguous here, you may know how valid? works, but I'm asking whether something else exists that behaves like a wrapper, I don't know how the spec system works in depth yet
No, the only way for spec to decide if a function follows the spec or not is to generate inputs from the spec and attempt to call the function on them
Immediately is not ambiguous at all
If you call valid? In the repl you get an answer back right there
sorry I don't mean to argue about the behaviour of valid?, I'm asking about what the spec system can do
the manual page has examples of using specs in the post and pre conditions of functions
Sure, calling valid? there to check arguments
But if you call valid? on a function it will generate data to check it
For data it can just walk it to see if it follows the spec
My answer starting with "No ..." above doesn't mention valid? and is a broad statement about spec itself
ty I see, so there are no analogues to e.g. racket function contracts?
Just manually calling valid? to check arguments that are not functions against a spec
hm I see, ok tyvm for your time
I haven't found spec'ing functions to be super useful, but spec'ing data to both validate data at runtime or generate it in tests can be very nice
hm when you spec data, do you explicitly call an assert or a valid?, or is there something similar to function input instrumentation that automatically enables checking at runtime?
When I have done it I call assert and valid? both, valid? is just a predicate so you need something like assert to do something with the result
I see ty!
It needs to be instrumented.
By default Spec only instruments the input. But you can use 3rd party libs like: https://github.com/jeaye/orchestra to instrument everything.
There's also https://github.com/fulcrologic/guardrails that gives you a replacement defn with fancier syntax for define the function spec.
very neat, ty!
is there a way to define a coll-of or every spec such that the error message on assert only reports the high-level collection failed spec, not the concatenation of all individual failures for each element of the collection?