This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-25
Channels
- # announcements (8)
- # babashka (58)
- # beginners (59)
- # biff (4)
- # calva (39)
- # cider (2)
- # clj-kondo (8)
- # clj-together (4)
- # cljdoc (5)
- # cljsrn (1)
- # clojure (60)
- # clojure-australia (2)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (3)
- # clojurescript (13)
- # conjure (10)
- # cursive (9)
- # datomic (5)
- # dev-tooling (1)
- # emacs (6)
- # events (1)
- # graalvm (38)
- # graphql (5)
- # joyride (1)
- # kaocha (3)
- # lsp (23)
- # malli (2)
- # mount (2)
- # off-topic (31)
- # other-languages (13)
- # pathom (3)
- # polylith (12)
- # portal (4)
- # practicalli (22)
- # re-frame (6)
- # reagent (3)
- # releases (3)
- # sql (4)
- # squint (3)
- # tools-build (10)
- # tools-deps (10)
- # xtdb (4)
Yo, I have a hiccup expression like this
[:div
(map-indexed (fn [i n] [:span (str "Task " i ": " n)]))]
This doesn't work because map-indexed returns a collection, rather than spread/flatten the result into the parent vector (duh)
I saw that you can use (for
for list comprehensions like this, but it doesn't look like it supports indexes very well. I could for
over (map-indexed vector coll)
but I imagine there's a more idiomatic wayThere is no difference in using for
or map
/`map-indexed`: All of these return lazy sequences.
I thought that this works for hiccup, as it supports and auto-flattens sequences? I could be mistaken though and only Reagent’s version supports this.
The beauty of hiccup is that, like so often when programing Clojure: it’s just data.
So you can just use code that produces the output you want.
In your case, try into
:
(into [:div] (map-indexed (fn [i n] [:span (str "Task " i ": " n)]) tasks))
This will append the sequence to [:div]
Thank you, last I tried just map/map-indexed I got an error about the array, but I might have misread it and it was something else, I'll try it again, it's more elegant.
Finally when chaining transformations like this, I prefer using the ->>
threading macro:
(->> tasks
(map-indexed (fn [i n] [:span (str "Task " i ": " n)]))
(into [:div]))
Yeah it doesn't work, because it thinks it's a component
[foo bar]
component foo, argument bar
[[foo bar]]
component [foo bar]
no arguments, since [foo bar]
isn't a real component, it throws in runtime
I'll go with the into
approach, I like it better than the (for
, thanks 😄
Looks like you are using reagent?
Sorry, I missed that I didn't actually say that 😄
Then you should not need any of this. Just make sure to add a key
to every dynamic element
E.g. this should work:
[:div
(map-indexed (fn [i n]
^{:key i} [:span (str "Task " i)])
tasks)]
I get the following warning
Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
and nothing is renderedThis looks like a different problem outside of this snippet. Are you maybe calling a hiccup function with ()
instead of building vectors with []
?
Oh, I did something and now it works... I'm guessing some sort of paren order with Calva or something screwed it up
This code returns the transducer- are you sure that you're calling map-indexed
with two arguments?
[:div
(map-indexed (fn [i n] [:span (str "Task " i ": " n)]))]
Yeah, I think the collection was one bracket outside too many
Good spotting, I somehow auto-corrected and added the tasks
in my examples ;D
I didn't read the whole thread, but any collection should work. Did you arrive at the point yet where you realised the original example missed the collection argument?
I see this is a common pain point lol
I'd start with (cljs.pprint/pprint structure)
=> (cljs.pprint/pprint [:div {:style {:display "flex"}
:overflow-y "auto"
:height "100vw"}
[:table {:border 0
:style {:border-collapse "collapse"
:flex-shrink 0}}]])
[:div
{:style {:display "flex"}, :overflow-y "auto", :height "100vw"}
[:table
{:border 0, :style {:border-collapse "collapse", :flex-shrink 0}}]]
Seems to do a decent job of it@U24MDANHY
I mean the resultant string from a call to hiccup.core/html
for example. The str returned is in a single line.
If you're on clojure and not clojurescript, it uses clojure-lsp
under the hood
No harm done. Perhaps I should send it to browser and inspect there but REPL is faster
You should be able to parse the resulting HTML string using sth like https://github.com/clj-commons/hickory. "HTML can be parsed into hiccup vectors, or into a map-based DOM-like format very similar to that used by clojure.xml. "
More fun might be a quick hack to add line breaks in front of opening tags, identified with clever regex, and even identifying depth to be used for indentation. That way you can see the raw string, just formatted.
Bonus points for figuring out cl-format
's arcane syntax and doing it all in ten lines. :)
Regex may not be able to parse html, but that does not mean it cannot parse an html tag. Clojure with a sprinkle of regex is certainly powerful enough to get the job done correctly, especially if you know the source is well-formed because it was generated.
(seq? '(1)) ; => true
(if (seq '(1)) true false) ; => true
(seq? '()) ; => true
(if (seq '()) true false) ; => false
I find it confusing. If seq? on empty list gives true, then creating a seq from empty list should be possible.
What do you think?
seq creates an object that satisfy ISeq interface. what is empty sequence in this constrains?
It's been a hot debate in Lisp circles about the equivalence of nil
and the empty list ()
and whether the empty list should test truthy or falsey etc.
It's a deliberate design decision of the language, it was decided that an empty seq would be nil
instead of the empty list.
=> (seq '())
nil
@U04V4KLKC 'seq creates an object that satisfy ISeq interface.'
So why
(seq? '()) ; => true
It doesn't satisfy ISeq interface
(seq? (seq '()))
false
Which is pretty funny, tbh
how? list implements ISeq. it doesn't matter if it is empty or not
It does seem a bit arbitrary/confusing that (seq '())
should return nil
though, instead of the empty list. But on the other hand, I also know that the empty list is itself a pretty special/confusing value
@UPBB20W20 (seq? '())
isn't false because empty list still the list which implement ISeq. looks like the main point of confusion is that seq and seq? functions somehow connected but in fact those are two independent things that share only one in common - they both use ISeq interface somewhere in implementation.
thank you @U04V4KLKC @U24MDANHY for explanation 😄
I have found example on 4clojure https://4clojure.oxal.org/#/problem/22 but to not use 'count'
so using (seq x)
in that way is kind of confusing for me, but probably it should not be used in that way, always better to use 'count'
(#(loop [x %
c 0]
(if (seq x)
(recur (rest x) (inc c))
c))'(1 2 3 4 5))
(rest sequence)
accepts a sequence, and returns a sequence of the remaining elements, or nil
, if there are no elements remaining - generally speaking, you should be asking (if (seq? x)
rather than (if (seq x)
I could disagree, it is advisable in clojure to use ideom (seq x)
to check when collection is not empty. See docstring for empty?
https://clojuredocs.org/clojure.core/empty_q
The idiom of using (seq foo)
as a test expression only works because seq
returns nil for an empty list.
nil
is a falsy predicate value. A list is still truthy, even if it is empty.
(boolean nil) ; false
(boolean (seq '()) ; false
(boolean '()) ; true
(defn reverse [m]
(loop [m1 m m2 nil]
; If seq returned '(), this would be infinite
; loop, but emptiness is signaled by nil.
(if (seq m1)
(recur (rest m1)
(cons (first m1) m2))
m2)))
The fewer things that need to be remembered, the better. I want my brain to be doing as little mental compilation/translation as possible when reading code.
(seq? coll)
is a very specific test and a lot of things that are loosely non-empty sequences will return false
for seq?
@U24MDANHY A lot of people are surprised by the difference between seq?
and sequential?
and seqable?
I always slow down when I get into these obscure nuances with nil?, seq, blank, empty, yadda yadda. Common Lisp is cleaner here, but still can confuse. An empty list, eg, is a cons
, a structure, with two properties, car
and cdr
, both of which have the value nil. But it is a structure, with object identity! And thus it is truthy! So we do not intiate a property with '()
or (list)
, we just say nil
. Then (when my-list ...) Just Works(tm), and it means
(when {my-list is populated]...)`. ie we do not distinguish an empty list from "this app never even decide a list should exist".