This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-11-03
Channels
- # announcements (35)
- # aws (20)
- # babashka (4)
- # beginners (88)
- # cider (9)
- # clara (1)
- # clj-kondo (6)
- # cljsrn (3)
- # clojure (107)
- # clojure-dev (7)
- # clojure-europe (99)
- # clojure-nl (3)
- # clojure-spec (9)
- # clojure-uk (2)
- # clojurescript (28)
- # core-async (53)
- # cursive (11)
- # datascript (1)
- # datomic (2)
- # emacs (20)
- # fulcro (3)
- # graalvm (4)
- # holy-lambda (18)
- # jobs (1)
- # kaocha (7)
- # leiningen (2)
- # lsp (25)
- # luminus (1)
- # membrane-term (52)
- # missionary (8)
- # nextjournal (19)
- # off-topic (16)
- # other-languages (3)
- # podcasts-discuss (2)
- # polylith (23)
- # re-frame (4)
- # reclojure (6)
- # remote-jobs (1)
- # rewrite-clj (36)
- # ring (1)
- # sci (10)
- # shadow-cljs (7)
- # spacemacs (5)
- # sql (20)
- # uncomplicate (1)
- # vscode (3)
- # xtdb (27)
@lilactown Or publish a gist (which can have multiple files and can be consumed as a git dep, at least by the CLI)... for example... https://gist.github.com/seancorfield/6e8dd10799e9cc7527da5510c739e52f
If I want to capture the current namespace into a symbol, how do I do it? So imagine:
(def x (symbol ??? "system"))
I know thereās *ns*
but I donāt know if it always points to the right thingā¦but your solution is even better
the reader will use the value of *ns*
to fill in the namespace in both of those forms
(binding [*ns* (find-ns 'user)] [(read-string "::test") (read-string "`x")]) ;; => [:user/test (quote user/x)]
so I guess it depends on what you mean by "always points to the right thing" ... šIām wondering what ways there are to clean this up. https://gist.github.com/wildwestrom/819879253abe69a3c3340f7cc3985224
This is my attempt at converting a dictionary written in XML into nice Clojure data. As you can see, the main bulk of the work is done by this one giant function called kanji-data
.
There are a few small things I would write differently, namely:
ā¢ Using ->
when appropriate instead of ->>
(more details at https://stuartsierra.com/2018/07/06/threading-with-style)
ā¢ Using transducers instead of creating lazy sequences
ā¢ Using cond->
where appropriate
ā¢ Not using type hints, like ^map
(use either :post
for that or just the docstring)
ā¢ Clarifying why sorted-map
is used instead of just {}
I used sorted-map
to maintain the order of the elements. I donāt think that was necessary.
Changed it to this:
(fn [x] {:reading x :type "ja_nanori"})
Is there a way to write this with a shorthand fn?
This does not work, and I donāt know why.
#({:reading % :type "ja_nanori"})
No, there's no shortcut. Your fn
form is the shortest one. You can create a macro for that, but I wouldn't do it given that it would make it much more opaque while saving just a few characters.
Alright cool, I donāt mind using fn
anyway.
I kinda like how this one turned out
(cond-> {val-key (first (:content x))}
(and (some? attr-key) (some? attr-lookup))
(conj {attr-key (attr-lookup (:attrs x))}))
If you know for sure that attr-key
and attr-lookup
can never be false
, then just drop some?
and use the values as they are.
Also, I wouldn't use conj
to add a key to a map - the most common approach is to use assoc
. The intent is much more clear given that conj
works on anything and assoc
works only on associative collections.
I understand that about nil
. My point is that if the false
value is not in the domain of variable x
, (some? x)
can be replaced with just x
since there are only two false-y values in Clojure - false
and nil
.
Itās true that my attr-key
Ā andĀ `attr-lookup` will never be false, but why wouldnāt I use some?
? Itās the same as (not (nil?))
right?
(and nil nil)
;; => nil
(some? nil)
;; => false
Anyway, I could also go with this:
(defn elem->maps
[element {:keys [attr-key attr-lookup val-key]
:or {val-key :val}}]
(mapv (fn [x]
(cond-> {val-key (first (:content x))}
(not-any? nil? [attr-key attr-lookup])
(assoc attr-key (attr-lookup (:attrs x)))))
(vec element)))
or this:
(every? some? [attr-key attr-lookup])
Because in that case (some? x)
is exactly the same as just x
. But it's an extra form and an extra check.
Instead, you can write:
(cond-> {val-key (first (:content x))}
(and attr-key attr-lookup)
(assoc attr-key (attr-lookup (:attrs x))))
Oh, I get it! cond
will read nil
as false.
I thought for some reason it would behave differently.
Not just cond
or cond->
in this case. Everything in Clojure that accepts a boolean value will treat nil
as false
, except for false?
.
Iām looking in to them as a potential mechanism for sending particular users prompts for feedback
If you're waiting for replies a websocket may be more appropriate. SSE is mostly for unidirectional communication, like subscribing on stock price updates
With SSE you keep a connection open, you have to ensure the client doesn't disconnect, and you depend on the client's implementation, too. As a server you can't initiate it, it has to be initiated by the client anyway. Both solutions have trade offs, but in terms of implementation SSE feels more annoying to deal with
> not really, also web sockets have spotty support depending on the browser Really? I mean, all major browsers, including IE 10, have supported WS since 2012. What browsers still have bad support in 2021?
Is there any way to look (temporarily) at the outer binding of a dynamic variable from inside a bound-fn
?
not sure but you could bind it to another var or local binding before using bound-fn
Yeah, that doesn't help here in this case, but it's something I'll keep in mind if I run into something similar in future.
The current problem I don't have control over the consuming code that's actually writing the bound-fn
call, I'm just writing some code that wants to be aware of if it's inside of one.
I think I was able to figure out a solution to my actual problem by just using a little constrained mutability though.
Trying to figure out a little data transformation puzzle:
ā¢ I have a list of strings with a start 0
and end 1
marker
ā¢ Sometimes I get them split up by the API Iām working with, e.g. ["0a1" "0b1" "0c" "c1" "0d1"]
ā¢ And I want to transform this list so that I get ["0a1" "0b1" "0cc1" "0d1"]
Consider the problem of String -> AbstractSyntaxTree. Solving this problem is called Parsing, and we can solve it via Regex + LL / LALR / Peg / Parsec / ... . In particular, we can view Regex / Peg as "DSLs" for String -> AbstractSyntaxTree Now, suppose we are trying to define a DSL -- which can be viewed as a subset of s-exprs. For example, Scheme is a "s-expr DSL"; Lisp is a "s-expr DSL", edn is a "s-expr DSL", clojure is a "s-expr DSL" -- in all 4 cases, all valid data values look like s-exprs. Question: What is the Regex / Peg equiv for doing "s-expr -> DSLs" ? I.e. what is a "pattern description language" for specifying what subset of s-exprs are valid exprs in the DSL ?
@zengxh That works but I forgot to mention that this is all async and that I canāt just have āthe entireā list
Infact, parts of spec internal use a parsing algorithm, just over elements in a sequence instead of tokens from a stream
What Iām trying to achieve is definitely possible with reduce
but Iām trying to maintain the sequential format since I want to eventually emit those events as they become available
depending on the possible error conditions i guess. not sure what invariants and guarantees your data has
I donāt think partition-by
works here though? Like Iām assuming you mean to use it to get to something like ["0a1" "0b1" ["0c" "c1"] "0d1"]
but Iām not sure how Iād do that with partition-by
?
(("0a1") ("0b1") ("0c" "c1") ("0d1"))
. that seems straightfoward to me. then you just join the collections and youāre in business
(let [pat #"0.*1"]
(into []
(comp (partition-by (fn [x] (re-matches pat x)))
(map #(apply str %)))
["0a1" "0b1" "0c" "c1" "0d1"]))
["0a1" "0b1" "0cc1" "0d1"]
alright, that does seem to work with the broken down example but Iām afraid I broke it down a bit too much.
In reality the chunks can be cut apart pieces of a bigger string like
some thing
another thing
this also belongs to another thing
yet another thing
belongs to above line, 2 newlines are the separator
and so on...
I might have lied a little bit (unintentionally). Basically thereās only a single separator not a start and end marker.
And the single separator is \n\n
no it could be split like
some thing
another thing
this also belongs to another thing
yet another thing
belongs to above line, 2 newlines are the separator
and so on...
i.e. in this case the split sits āinsideā the string I want to extract
still not a great description of the problem, but it sounds like it reduces to the same problem
this is a sample of inputs
["thing 1\n\n"
"thing2: "
"also thing2\n\n"
"thing3\n\n"]
and the goal:
["thing1\n\n"
"thing2: also thing2\n\n"
"thing3\n\n"]
So (.split % "\n\n")
doesnāt really do much in this case I think
sorry for my poor articulation of the problem, I tried to simplify it but some properties got lost
user=> (->> data (mapcat #(if (.contains % "\n\n") [% :split] [%])) (partition-by (partial = :split)) (remove #{[:split]}))
(("thing 1\n\n") ("thing2: " "also thing2\n\n") ("thing3\n\n"))
user=>
thatās smart
i think that fails if one entry contains multiple broken "entry 1\n\nentry2\n\nentry3\n"
`ācontinuing entry3\n\nentry4ā`
it does, which is what the interpose stuff was about up above, interpose isn't entirely right alone either, you need to interpose (in case of internal splits) and append a split at the end
I think that might not happen
spoke to soon, that does happen š
but I think I can figure that out now š
Thanks for your help Kevin and Dan!
@hiredman: is there a unified theory behind spec, or is it a collection of really useful battle tested tricks glued together ?
The parsing algorithm that is used to some degree internal in spec is parsing with derivatives
there were/are other clojure libraries that predate spec that define regexs over sequences
Iām using #missionary which in theory allows me to manage that state in a transducer but havenāt worked it out yet š
I do basically exactly this with Gloss and Manifold streams (in a TCP context but no reason it can't work with pure data).
@thom704 interesting, the context Iām in is Server-Sent-Events and consuming those using js/fetch
How do you parse events on the server? Do you follow the spec? https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation
Seems like the implementation might be easy to share
user=> (def data ["0a1" "0b1" "0c" "c1" "0d1"])
#'user/data
user=> (distinct (for [x data y data :when (= (re-matches #"0.*1" x) (re-matches #"0.*1" y)) :let [joined (hash-set x y)] :when (and (some #(.startsWith % "0") joined) (some #(.endsWith % "1") joined))] joined))
(#{"0a1"} #{"0b1"} #{"0c" "c1"} #{"0d1"})
user=>
Hi, how do I insert a map into a vector of maps at a specific location
(defn insert-before [vector label-key value]
...
)
user => (insert-before
[{:label "A" :val "foo"}
{:label "C" :val "baz"}]
"C"
{:label "B" :val "bar"})
[{:label "A" :val "foo"}
{:label "B" :val "bar"}
{:label "C" :val "baz"}]
By using a combination of subvec
and into
.
(let [insert-at-idx (...)
v [...]
item ...]
(-> (subvec v 0 insert-at-idx)
(conj item)
(into (subvec v insert-at-idx))))
thanks I implemented insert-at-idx
function just prior but I realized that I wonāt have the index when I need to call the function
are you suggesting implementing my function insert-before
by composing insert-at-idx
and a get-index
function?
I don't know what "insert-at-idx function" is - in my snippet above it's the index itself.
what is the function to get the index?
in the example above the element with :label "C"
is 1