beginners

Shantanu 2025-05-25T10:00:29.781119Z

is it possible to access the result of a test in a cond in it's corresponding branch?

(cond ...
      (some-test? args) test-result
      ...)

Shantanu 2025-05-25T10:01:15.733209Z

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

Shantanu 2025-05-25T10:01:54.342189Z

so basically is there a cond-let or something similar to if-let that we have

Shantanu 2025-05-25T10:06:22.061739Z

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

oλv 2025-05-25T10:10:27.361079Z

Nested if-lets

Shantanu 2025-05-25T10:10:44.802449Z

yeah this is what I'm doing at the moment

Shantanu 2025-05-25T10:10:54.297329Z

I guess that's the only approach...

oλv 2025-05-25T10:13:50.033189Z

You can make your own macro, or use a utility lib

Shantanu 2025-05-25T10:14:18.869059Z

will check it out, thanks!

Shantanu 2025-05-25T10:14:32.804429Z

although for now memoise is a good enough hack

🔥 1
p-himik 2025-05-25T11:26:15.235949Z

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.

p-himik 2025-05-25T11:28:22.593199Z

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)))

Shantanu 2025-05-25T11:33:55.782799Z

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?

Shantanu 2025-05-25T11:35:15.348669Z

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

p-himik 2025-05-25T11:39:23.206569Z

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.

Shantanu 2025-05-25T11:40:38.920279Z

ah my bad, I switched to indentation block semantics in my head 😳

2025-05-25T16:20:32.347719Z

> is it possible to access the result of a test in a cond in it's corresponding branch? this is what condp is for

2025-05-25T16:22:57.157589Z

well - maybe not a perfect fit here, but often this can be squeezed into the shape condp needs with the right pred arg

2025-05-25T16:24:54.382739Z

eg (example from docs website)

(condp some [1 2 3 4]
  #{0 6 7} :>> inc
  #{4 5 9} :>> dec
  #{1 2 3} :>> #(+ % 3))

2025-05-25T16:25:56.169199Z

https://clojuredocs.org/clojure.core/condp

Shantanu 2025-05-25T17:07:45.550959Z

The :>> is new will check out, thanks!

2025-05-25T17:13:28.352489Z

condp might be a bad fit here as it uses the same comparison function at each step

2025-05-25T17:13:57.480739Z

but its behavior reminded me of what you wanted, it might match your use case if you massage it right

Shantanu 2025-05-25T17:17:46.008209Z

not in this case, but definitely good to know

phronmophobic 2025-05-25T18:13:07.155959Z

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.

p-himik 2025-05-25T18:17:37.929899Z

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.

VardriPoise 2025-05-25T15:02:42.360009Z

what are currently some of the most popular libraries for writing web APIs in clojure?

practicalli-johnny 2025-05-25T16:51:33.607199Z

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/

2025-05-25T18:32:12.564529Z

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

2025-05-25T18:37:22.714959Z

The second most popular after that is Pedestal probably: https://github.com/pedestal/pedestal

VardriPoise 2025-05-25T20:36:14.781069Z

thank you all for the suggestions, I'll be looking into these!

VardriPoise 2025-05-25T01:21:03.130459Z

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

2025-05-25T01:24:04.968949Z

How else would it tell if a function is valid?

VardriPoise 2025-05-25T01:25:10.401909Z

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

2025-05-25T01:25:50.674109Z

But valid? returns true or false right away

2025-05-25T01:26:11.505089Z

How would it know if those pre/posts are triggered?

VardriPoise 2025-05-25T01:26:25.387479Z

is it a macro?

2025-05-25T01:27:07.654019Z

Even if it was, how could it immediately return true or false by instrumenting the function?

VardriPoise 2025-05-25T01:28:05.372829Z

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

2025-05-25T01:28:17.447099Z

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

2025-05-25T01:28:30.542479Z

Immediately is not ambiguous at all

2025-05-25T01:29:12.702209Z

If you call valid? In the repl you get an answer back right there

VardriPoise 2025-05-25T01:29:43.419679Z

sorry I don't mean to argue about the behaviour of valid?, I'm asking about what the spec system can do

VardriPoise 2025-05-25T01:30:11.687939Z

the manual page has examples of using specs in the post and pre conditions of functions

2025-05-25T01:30:31.345559Z

Sure, calling valid? there to check arguments

2025-05-25T01:30:50.782119Z

But if you call valid? on a function it will generate data to check it

2025-05-25T01:31:15.972019Z

For data it can just walk it to see if it follows the spec

2025-05-25T01:32:55.332949Z

My answer starting with "No ..." above doesn't mention valid? and is a broad statement about spec itself

VardriPoise 2025-05-25T01:33:29.005989Z

ty I see, so there are no analogues to e.g. racket function contracts?

2025-05-25T01:34:14.109439Z

Just manually calling valid? to check arguments that are not functions against a spec

VardriPoise 2025-05-25T01:34:50.042759Z

hm I see, ok tyvm for your time

2025-05-25T01:36:04.619509Z

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

VardriPoise 2025-05-25T01:37:45.970639Z

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?

2025-05-25T02:01:53.800419Z

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

VardriPoise 2025-05-25T02:21:59.893009Z

I see ty!

2025-05-25T03:17:54.284319Z

It needs to be instrumented.

2025-05-25T03:21:37.493619Z

By default Spec only instruments the input. But you can use 3rd party libs like: https://github.com/jeaye/orchestra to instrument everything.

2025-05-25T03:34:15.249949Z

There's also https://github.com/fulcrologic/guardrails that gives you a replacement defn with fancier syntax for define the function spec.

VardriPoise 2025-05-25T03:56:26.401569Z

very neat, ty!

VardriPoise 2025-05-25T04:52:07.994239Z

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?