This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-19
Channels
- # announcements (15)
- # babashka (4)
- # beginners (55)
- # calva (92)
- # cider (70)
- # circleci (1)
- # clj-kondo (136)
- # cljdoc (2)
- # clojars (11)
- # clojure (48)
- # clojure-australia (1)
- # clojure-europe (30)
- # clojure-nl (3)
- # clojure-sweden (2)
- # clojure-uk (7)
- # clojurescript (40)
- # conjure (5)
- # core-async (11)
- # cursive (55)
- # data-science (1)
- # datomic (10)
- # degree9 (2)
- # development-containers (15)
- # events (1)
- # fulcro (14)
- # gratitude (13)
- # helix (5)
- # lsp (35)
- # malli (10)
- # meander (18)
- # off-topic (24)
- # pathom (13)
- # polylith (12)
- # practicalli (6)
- # re-frame (13)
- # reagent (33)
- # reitit (4)
- # remote-jobs (1)
- # shadow-cljs (13)
- # spacemacs (31)
- # specter (1)
- # stepwise (2)
- # tools-deps (19)
- # vim (1)
- # xtdb (7)
Why isn't halt-when implemented like:
(defn halt-when'
[pred]
(fn [rf]
(fn
([] (rf))
([done] (rf done))
([acc e] (if (pred e) (reduced (rf acc e)) (rf acc e))))))
(transduce
(halt-when' #{4})
conj
[1 2 3 4 5 6 7 8 9])
[1 2 3 4]
Or is there another transducer that does this?I think that halt-when
should stop when the predicate returns true, and not include the result. However, it tries to give you a function to give you a strategy for what to do when it does, so you can decide what to do. But I think there's a problem with the way it's implemented. Firstly, it seems to return input
where it should be returning the result:
(into [] (halt-when #{4}) (range))
class java.lang.Long cannot be cast to class clojure.lang.ITransientCollection (java.lang.Long is in module java.base of loader 'bootstrap'; clojure.lang.ITransientCollection is in unnamed module of loader 'app')
So I think this stops it from throwing class cast exceptions:
(defn halt-when1
([pred] (halt-when1 pred nil))
([pred retf]
(fn [rf]
(fn
([] (rf))
([result]
(if (and (map? result) (contains? result ::halt))
(::halt result)
(rf result)))
([result input]
(if (pred input)
(reduced {::halt (rf (if retf (retf result input) result))})
(rf result input)))))))
(into [] (halt-when1 #{4}) (range)) ;; => [0 1 2 3]
However, I think that the retf
function is now coupled to the transducing context. So if you want to include the 4
then you need to know when you create the transducer that it will be used in a specific context and that you need to call conj
or conj!
or whatever. So I think that this signature of the function makes more sense:
(defn halt-when2
([pred] (halt-when2 pred nil))
([pred retf]
(fn [rf]
(fn
([] (rf))
([result]
(if (and (map? result) (contains? result ::halt))
(::halt result)
(rf result)))
([result input]
(if (pred input)
(let [r (if retf
(retf rf result input)
result)]
(reduced {::halt (rf r)}))
(rf result input)))))))
and now you get to actually decide what to do:
(into [] (halt-when2 #{4} (fn [rf r i] (rf r i))) (range)) ;; => [0 1 2 3 4]
Does that make sense?I've asked this here: https://ask.clojure.org/index.php/10955/halt-when-transducer-throws-class-cast-exception-when-used cos I think it looks like a bug π
hmm ... ok ... just found this : https://groups.google.com/g/clojure/c/6HvmJIUsXKk/m/gLqUsfcnAwAJ
@didibus There's take-while
:
(into [] (take-while (complement #{5})) (range 10))
Greetings! I have a little conundrum: What is the correct type hint to use for the return type of something that returns {:a "map" :of "stuff"}
?
No type hint
Type hints are for Java interop. Thatβs Clojure data and no type hint is needed
There are situations in which returning a hint for such a defn is justified. What are you trying to do / why?
when naming is ambiguous, it helps to quickly check if I'm returning a list or a map on things like scan-datapoints
(defn ^String foo [] {:x 1})
(foo) ;; => {:x 1}
Type hints can liefair enough. This is old code that I'm going through, so adding hints was another way to make things readable without changing it for now
In principle type hints are the wrong tool for documentation. It's objective - it often will emit technically wrong code Docstrings or Spec are more idiomatic
If you want to actually make a checkable descriptive result, write a spec
but while figuring out the call stack it helps to see what is going around many levels deep
Yes, the problem with type hint is that the wrong hint will potentially break things or hurt performance. Where as wrong doc or spec won't
Yes or bespoke metadata like ^{::kind :map}
if you feel that helps you during refactoring
Anything but abusing type hints π
The use case #2 per https://github.com/stathissideris/spec-provider/tree/f9e4b3a9a54752a1c2c8df0291ff517679442a1a#use-cases would be interesting here (TIL about that specific capability from spec-provider... that's why I love answering questions :) )
(defn foo
^:String [^:int a ^:int b]
(str a b))
Because if you add type hints, and the hint is wrong, you can technically break the code or slow down the performance of itI don't actually recommend this, I think doc-string or spec is better, but if you insist on having the type inline, plain meta doesn't have the risk that type hint does.
You could also consider pre/post and something like Truss, that would also give you a guarantee your types are somewhat correct: https://github.com/ptaoussanis/truss#assertions-within-prepost-conditions and is more lightweight than full-blown specs
Hi there, what is the pattern for merging maps keeping into consideration subtractive operations? (i.e. (merge m1 m2) where a key in
m2` does exist at all).
I know merge-with
would not work in this case because there is not key in m2
@richiardiandrea I think you'd need to do (select-keys m1 (keys m2))
for that?
ah cool yeah that would definitely work...
Thank you Sean I felt I was missing some core function but after a bit of googling it seems I am not missing anything
(and then merge m2 into that)
let's say I have some process that could produce one or more results, possibly in an asynchronous manner. a consumer would want to handle the results in order until the process is complete, like pipe the results to a web client. is there some generic interface I could put in front of this process so that I wouldn't have to pick one particular async lib (i.e. core.async, manifold, etc.)?
I think callbacks are often the most general and can be adapted into any of the other abstractions
I tried something similar, ended up having the API with core.async for simplicity (in my case the clients implementations where using core.async anyway), but in case it can be of use:
(defprotocol Handler
:extend-via-metadata true
(handle* [this val cb] "Handle new value, calls cb with true if value was handled properly, false otherwise"))
(extend-protocol Handler
Fn
(handle* [this val cb] (try (this val)
(cb true)
(catch Exception _
(cb false))))
ManyToManyChannel
(handle* [this val cb] (try (a/put! this val cb)
(catch Exception _
(cb false)))))