This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-01-20
Channels
- # announcements (30)
- # babashka (118)
- # beginners (23)
- # calva (68)
- # cljdoc (10)
- # clojars (13)
- # clojure (90)
- # clojure-bangladesh (1)
- # clojure-europe (27)
- # clojure-gamedev (1)
- # clojure-nl (11)
- # clojure-uk (4)
- # clojurescript (59)
- # community-development (3)
- # cursive (13)
- # datomic (39)
- # defnpodcast (1)
- # emacs (10)
- # figwheel-main (1)
- # fulcro (18)
- # graalvm (21)
- # honeysql (1)
- # introduce-yourself (1)
- # juxt (1)
- # lsp (197)
- # malli (19)
- # off-topic (28)
- # practicalli (2)
- # re-frame (42)
- # reagent (4)
- # reitit (7)
- # releases (2)
- # sci (35)
- # shadow-cljs (13)
- # spacemacs (4)
- # vim (3)
Why doesn't flatten
flatten sets?
(flatten #{1}) ;; ()
(flatten (into [] #{1})) ;; (1)
sets are not sequential things:
Takes any nested combination of sequential things (lists, vectors,
etc.) and returns their contents as a single, flat lazy sequence.
(flatten nil) returns an empty sequence.
I think it does have its uses though 🙂 I have a sequence of keyword string pairs like: '([:a "a"] [:c "c"])
and I want to get all the keywords.
So (filter keyword? (flatten myseq))
.
Flatten is wrong here, too, at least you should (apply concat ,,,)
But why not just (filter keyword? (map first xs))
?
indeed. A hash-map with keys
would be the way to go. For example you could use
(keys (into {} coll))
If you into {}
` a 2-element-each seq, it will give you a hash-map.I appreciate the tips 😄
flatten
works with sequential things and set is not sequential
(sequential? #{}) ;; => false
user=> (into [] (comp cat (filter keyword?)) '([:a "a"] [:c "c"]))
[:a :c]
user=> (filter keyword? (tree-seq coll? seq '([:a "a"] [:c "c"])))
(:a :c)
If this is only for the first element of the pair any form of flattening is actually a bug, consider ([:a :b])
Is there a blog post or something about why flatten is so bad? It seems innocuous XD
There are two problems, it eats up everything, which is a polite way of saying "I don't know what my data looks like", which holds up right until your data contains something you did not expect and you get a bug Second is terrible performance. There's always another solution which is more specific to what you actually want to accomplish
The latter is a very good point! When using flatten the code says little about what your data looks like.
I'll take it farther. Code is a medium of communication, what are you communicating to yourself when you use flatten? "I'm not sure what's in this, fingers crossed". Does that make you uncomfortable? It should 🙃
-----------
Does anyone want to speculate why stuartsierra/dependency
does not allow one to add unconnected nodes? https://github.com/stuartsierra/dependency/blob/master/src/com/stuartsierra/dependency.cljc
I've found a workaround: add a dependency between the node you want to add and a dummy and then remove the dummy afterward. Feels clunky though.
(def g (dep/depend (dep/graph) "a" :dummy))
;; => #'user/g
user> g
;; => #com.stuartsierra.dependency.MapDependencyGraph{:dependencies {"a" #{:dummy}},
:dependents {:dummy #{"a"}}}
user> (dep/remove-all g :dummy)
;; => #com.stuartsierra.dependency.MapDependencyGraph{:dependencies {"a" #{}},
:dependents {}}
It does keep the library minimal though. Perhaps I like this design choice.
Perhaps because in dependency resolution there can be no unconnected nodes. A library is either a dependency somewhere or it's not used at all.
Yes, the origin is dependency resolution I see from the README.md.
hi all
question about regex
why
(str/split "'s-Hertogenboschplein Almere" #"\b")
works as expected (eg splits at word boundary), but (re-matches #"\b" "'s-Hertogenboschplein Almere")
returns nothing?
thanks
and more important question is
how can i split at word boundary expect when it is 's-
thus 's-Hertogenboschplein
should not be splitted
re-matches
checks for a full match. Try (re-matches #"a" "ab")
- it will return nil
.
And #".*\b*.**"
will simply match any string that has at least one word character - there is a more obvious way to achieve that, via \w
.
what does it mean a full match
?
It means that the whole string matches the regex and not just any substring.
Same as if your regex had ^
and $
around it.
then another question how I can find word boundaries indecies?
Pretty sure you'd have to use interop with Java's Matcher
for that.
Construct a matcher using re-matcher
, then call .find
on it, check if it returns true
and if so, call .start
and save its return value. Repeat till .find
returns false
.
there is \W which marks the start of a non-word char. I haven't given it a lot of thought but you be able to use that too to find the index of the first non-word char
thanks, but I’ve picked totally different approach
there's re-find
and re-seq
in clojure too that don't match the whole string
doing re-seq
with \w
would give you a sequence of all the words
thanks!
As I understand some people have done some work on a monadic library for clojure. I’ve discovered a very interesting feature in Scala which I’ve also needed in clojure. Does the clojure mondic library have a foldM (monadic fold) function? It sounds exotic, but it really serves a useful purpose which does not depend on category theory to understand.
I believe the fluokitten lib has fold
taking a look at fold in https://github.com/uncomplicate/fluokitten/blob/master/src/uncomplicate/fluokitten/core.clj and it does not seem to do what I hoped it did. but I admit I don’t understand the code.
do you really need an abstract monad interface, or are you implementing this for a specific monad? i.e. a list or option
The issue I’m referring to is that the clojure reduce
function has a sister function called reduced
which sometimes allows you to escape (return early) from the fold operation, when you’ve found the value you’re looking for, or when your iteration has converged. The problem is that it does not work on reentrant code. if you have the function passed to reduce
calls another function which itself calls reduce
, then reduced
only returns from the inner-most reduce
, not the reduce
it is lexically within.
you can of course detect this case and there are some places we do this inside transducers
with things like reduced?
and other related are ensure-reduced
and unreduced
interesting. is the case always detectable or sometimes detectable?
reduced is just a wrapper, so you can always detect that a value is a reduced value with reduced?
if the outer reduce checks for a reduced value from the inner reduce, it could return it directly (or use ensure-reduced
) or whatever
what if the outer function does not know a black-box function it is calling is implemented in terms of reduce/reduced
?
for example an old implementation was using recursion, and it gets refactored to use reduce, it might start failing if the function that is calling it used ’reduced`.
right?
or perhaps a better example, can I used reduced
when reducing a lazy list?
I'll need to check to make sure but I think the cat
transducer satisfies this property, might be worth checking how it's implemented
this is a little too abstract for me, do you have an example?
Is it possible to make a record destructure like a vector (`(let [[k v] (->record 1 2)] [k v])` produces [1 2]
)?
(defrecord hi [a b])
(def r (->hi 1 2))
(let [{:keys [a b]} r] [a b]) ;; [1 2]
Or does @U0232JK38BZ answer your actual question? (I read, “I really wanna do it positionally. How?” when maybe you meant, “How do I destructure records in general?“)
I have a bunch of functions that expect a sequence of 1 or 2 element tuples (vectors), and I want to be able to write nested sequences of those tuples at the point of creation and then call flatten
without flattening the tuples themselves, so that the munging function converts from arbitrarily nested tuples to sequence of tuples
the easiest way to do this is with a map, but that requires changing all of the other functions too, which is annoying and needless because the concept of a “tuple” is all I need.
so i was thinking of implementing a protocol that would allow this destructuring on a record to make creation of the tuple not affect any other part of the app
If you know your map will only have 2 elements (i.e. it will always be an array-map), you can just call vals
to convert to a tuple, yeah?
I dunno, just throwing out random factoids at this point, because I don’t understand. 🙃
i’m sorry, i’ve not done a great job of describing this lol
All you need to do for this type of destructuring is to implement ISeq or ISeqable and make it so that you return a sequence of items in the order you want.
a valid input looks like [[:a 1] [:b [:example 2]] [:c]]
. when including conditions, I want to be able to write [[:a 1] (when condition [[:b [:example 2]] [:c]])]
instead of [[:a 1] (when condition [:b [:example 2]]) (when condition [:c])]
. there’s a single function get-fx
that consumes the input and then passes it to many other functions, all of which expect it to be shaped as a sequence of pairs. I can’t just call flatten
because the pairs sometimes only have 1 element and sometimes the second element in the pair itself is a pair or a vector
ope, interesting, okay
Don't use flatten
at all. Instead, I would wrap a conditional group of tuples in something and check for that something in a custom flattening function. Like [[:a 1] (when x? {:items [[:b 2] [:c 3]]}) [:d 4]]
.
If something is a tuple - let it be a tuple. Don't create artificial wrappers only so that you can use them with one very specific function.
interesting thought, thanks
Couldn't you do
(cond-> [[:a 1]]
condition (conj [:b [:example 2]] [:c]))
conj takes arbitrarily many arguments
oh hm, i forgot about cond->
. yeah, that would probably work here
also my favorite -> helper functions
(defn when-pred [value pred then]
(if (pred value) (then value) value))
(defn if-pred [value pred then else]
(if (pred value) (then value) (else value)))

I have found neither of these functions in this useful form in any of the utility libraries
this helps when you want to do cond->
but have each condition depend on the current value
@U5NCUG8NR That's why we wrote condp->
and condp->>
https://github.com/worldsingles/commons/blob/master/src/ws/clojure/extensions.clj#L24
I like that, although I think it's important to still have the functions for it to avoid the need for as->
in both the pred and function separately
which is definitely sometimes needed
Argh. We use timbre
for logging and it's been fine so far, we have com.fzakaria/slf4j-timbre
to make sure any logs from libs using slf4j end up going via Timbre. But I've just recently tried to add/work with 2 different libs that use ch.qos.logback/logback-classic
. Apparently both that and slf4j-timbre
provide a StaticLoggerBinder
implementation, so I get errors about multiple slf4j bindings and it picking one (the Timbre one).
For the first lib I fixed that by excluding logback-classic
, and haven't seen any issues thus far, but for the second lib it fails to load properly if I do that, and if I have both slf4j libs installed it bombs because it can't cast the Timbre adaptor to the logback classic Logger.
How can I resolve this? Can I make Timbre use logback-classic somehow, instead of the fzakaria module? Can I define a custom logger implementation to both, that is used instead of StaticLoggerBinder
, so that the compatibility isn't an issue?