This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-04-13
Channels
- # announcements (18)
- # babashka (11)
- # beginners (29)
- # biff (2)
- # cider (14)
- # clojure (98)
- # clojure-boston (1)
- # clojure-europe (5)
- # clojure-korea (2)
- # clojure-madison (1)
- # clojure-norway (2)
- # clojurescript (10)
- # community-development (5)
- # fulcro (8)
- # lambdaisland (1)
- # nbb (1)
- # nrepl (107)
- # pathom (4)
- # pedestal (5)
- # portal (1)
- # rdf (2)
- # reitit (7)
- # releases (1)
- # rum (2)
- # shadow-cljs (8)
- # squint (18)
- # timbre (3)
- # xtdb (18)
Hi 🙂
Thoughts on how to write a function that calls a macro with variadic arguments? Do I need to create a new macro to wrap the first macro?
I tried to use apply
as I would with a function, but that fails because I can’t treat macros as values.
(defn hiccup [& data]
(str (apply hiccup/html data)))
;; => Syntax error compiling at (src/teodorlu/jorm/fns.clj:10:8).
;; Can't take value of a macro: #'hiccup2.core/html
A mental model about macros is that they are compile-time stuff. When the enclosing function is actually invoked, the macro is not there anymore. Only the code it expanded into.
(hiccup.core/html (into [:div] html))
. You can give them fragments a single root
branch=> (let [html [[:div [:p "some text"]]
[:div [:p "more text"]]]]
(hiccup.core/html (into [:div] html)))
"<div><div><p>some text</p></div><div><p>more text</p></div></div>"
demo=> (defn render [& data] (hiccup.core/html (into [:div] data)))
#'demo/render
demo=> (render [:p "important text"] [:div [:p "other text"]])
"<div><p>important text</p><div><p>other text</p></div></div>"
for hiccup.core/html
specifically, I realized that it also accepts sequences / lists as input, so I could pass a list directly:
(str (hiccup/html [:div]))
;; => "<div></div>"
(str (hiccup/html [:div] [:p]))
;; => "<div></div><p></p>"
(str (hiccup/html (list [:div] [:p])))
;; => "<div></div><p></p>"
(= (hiccup/html [:div] [:p])
(hiccup/html (list [:div] [:p])))
;; => true
note the docstring of hiccup.core/html
says it returns a string. no need to add a str
call to it.
right. It appears I was using hiccup2.core/html
in the REPL above,
(hiccup2.core/html [:div])
;; => #object[hiccup.util.RawString 0x51c555c ""]
(:doc (meta #'hiccup2.core/html))
;; => "Render Clojure data structures to a compiled representation of HTML. To turn\n the representation into a string, use clojure.core/str. Strings inside the\n macro are automatically HTML-escaped. To insert a string without it being\n escaped, use the [[raw]] function.\n\n A literal option map may be specified as the first argument. It accepts two\n keys that control how the HTML is outputted:\n\n `:mode`\n : One of `:html`, `:xhtml`, `:xml` or `:sgml` (defaults to `:xhtml`).\n Controls how tags are rendered.\n\n `:escape-strings?`\n : True if strings should be escaped (defaults to true)."
looks like hiccup.core/html returns a string all right:
(require 'hiccup.core)
(hiccup.core/html [:div])
;; => "<div></div>"
Be careful of hiccup.core! Last I checked, it did not escape HTML controls - in other words, was vulnerable to injections. Hiccup2 seems less convenient (I haven't learned yet why I should want a compiled form of the HTML) but it appears to guard against injections.
One difficulty I have with clojure is trying to understand symbols. They behave different than in all other lisps I've used. For example, why does identical?
return false
here? (identical? 'xyzzy 'xyzzy)
this is something which always confuses me in clojure. every time I learn it, I later unlearn it. Are symbols re-allocated by the reader? Is it easy enough to understand why? Or is it too complicated and we just have to accept it as axiomatic?
Not axiomatic as not important. In Clojure symbols aren't places in memory, vars are. That means symbols don't have to be identifiers, so they don't have to be interned. Interning is an extra step, shouldn't be assumed to be the default. What IS guaranteed to be unique identifier is a Keyword, which can be thought of as symbols which refer to themselves
Offtopic: The discussion reminds me of General Semantics and its handling of names vs. referents.
Symbols can have metadata which differs per context, and thus they cannot be interned
Alex, that's a good description. Does that mean that vars cannot have metadata?
Vars also can have meta
> What IS guaranteed to be unique identifier is a Keyword,
Not in ClojureScript, where you're supposed to test keywords with keyword-identical?
instead of identical?
. One hopes that ClojureScript will solve that problem or Clojure will add keyword-identical?
...
@U064X3EF3 I’m not sure I understand the comment int hat case. symbols cannot be interned because they can have metadata. however vars CAN be interned even thought they can have metadata. Then metadata is not the reason for avoiding interning symbols. What did I fail to understand?
Isn't the difference the "which differs per context" part?
(defn my-var {:defined-at (java.util.Date.)} []
:foo)
(:defined-at (meta #'my-var)) => #inst "2024-04-16T08:51:49.398-00:00" ; same same
(:defined-at (meta #'my-var)) => #inst "2024-04-16T08:51:49.398-00:00"
(defn symbol-provider []
(with-meta 'foo {:created-at (java.util.Date.)}))
(= (symbol-provider) (symbol-provider)) => true
;; yet not same:
(meta (symbol-provider)) => {:created-at #inst "2024-04-16T08:48:42.753-00:00"}
(meta (symbol-provider)) => {:created-at #inst "2024-04-16T08:48:43.666-00:00"}
IIUC the desired behavior is that the var has consistent metadata (because my-var
is a reference to a single thing) and the symbol can have metadata specific to its context (because by design each 'foo
is https://www.clojure.org/guides/learn/syntax#_symbols_and_idents).I think it is important to separate equality and identity, and probably also to be more precise about what’s meant by “intern” (which I will avoid using because I think it’s confusing here). By definition, metadata does not participate in equality, so a symbol can be used in two places, have the same name, be equal, but have different metadata. Because they may have different metadata, they cannot be identical or reused. This is the answer to the original question - why are two symbols with the same name not identical. By comparison, keywords cannot have metadata, always compare equal, and thus the same identical instance can be reused in different contexts. This is in some sense an optimization in the jvm impl - it is not semantically wrong to implement keywords without identity (as in cljs). But it’s possible because no metadata. Vars are references, not values, and I would not even bring them into this discussion. Vars, as objects, have metadata, but they gain identity not via their implementation but via their mapping to a name in a namespace (they indelibly are a named “place”). Because a particular Var object always exists at a mapping name, referring to a var by name always resolves to the identical object.
I'm trying out rum for first time. i'm trying it with shadow-cljs and spacemacs practicalli config. I got lot of lint errors so I found that clj-kondo is giving them and adding a config for rum should solve it issues.
I added following line
[io.github.clj-kondo/config-rum-rum "1.0.0"]
but i'm getting error [shadow:watch ] shadow-cljs - dependency update failed - Failed to collect dependencies at io.github.clj-kondo:config-rum-rum:jar:1.0.0
see full error at https://pastebin.com/0JzsUhZ6
I researched some more and found i can use deps.edn together with shadow-cljs.edn and try other options (eg git dep) but I'm not too confident adding more moving parts so wanted to reach out here first
It is failing to resolve the name for the most used maven repo, http://repo1.maven.org