This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-07-22
Channels
- # announcements (6)
- # babashka (8)
- # beginners (136)
- # cider (5)
- # cljs-dev (1)
- # cljsrn (1)
- # clojure (198)
- # clojure-argentina (4)
- # clojure-australia (1)
- # clojure-europe (25)
- # clojure-italy (4)
- # clojure-nl (5)
- # clojure-poland (1)
- # clojure-spec (4)
- # clojure-uk (4)
- # clojuredesign-podcast (4)
- # clojurescript (36)
- # conjure (11)
- # data-science (1)
- # datomic (6)
- # defnpodcast (1)
- # deps-new (5)
- # emacs (7)
- # events (1)
- # fulcro (10)
- # graalvm (9)
- # graalvm-mobile (10)
- # helix (9)
- # introduce-yourself (1)
- # jackdaw (1)
- # jobs-discuss (5)
- # kaocha (6)
- # lsp (10)
- # malli (11)
- # missionary (28)
- # off-topic (2)
- # pathom (24)
- # pedestal (7)
- # portal (1)
- # re-frame (12)
- # reagent (2)
- # reitit (1)
- # remote-jobs (1)
- # sci (7)
- # shadow-cljs (6)
- # sql (6)
- # tools-deps (10)
- # vim (9)
- # xtdb (19)
Does anyone know how I can get syntax highlighting working in vim/neovim? First I tried everything according to this article: https://oli.me.uk/getting-started-with-clojure-neovim-and-conjure-in-minutes/ and still didn't get full highlighting, so then I tried fireplace + vim-clojure-highlight but honestly nothing changed after installing it. After both tries, I still don't get any highlighting on any imported functions (str/split) or functions defined within the same file. Even when they come immediately after open parens like (my-func xyz). Atom does this with no REPL and zero plugins, so I'm guessing this isn't a hard task. But I still can't seem to get it. Any advice?
There's a #vim channel that might be able to help @U0292NREWDP
Which vim/neovim version are you using?
@U7ERLH6JX Currently using Neovim 0.5
do you have the following in your init.vim?
filetype plugin indent on
syntax on
if youre using vimscript to configure?if you have your config checked in somewhere, im happy to look at it as well 😄
also if you're new to vim, let me know too and probably better to move it to the #vim channel like Sean mentioned, more of us can help you along better! 😄
@U7ERLH6JX Thanks, I will post to #vim channel
Anyone know a good library for working with Zotero?
And still no answers 🙂
What is Zotero? I've never heard of it.
"Zotero is a free and open-source reference management software to manage bibliographic data and related research materials." So not LaTeX but something like it?
Based on this it looks like it has a basic REST API so you could use any HTTP client library in Clojure to interact with it: https://www.zotero.org/support/dev/web_api/v3/basics -- we use httpkit at work because I like the simplicity of it (no troublesome dependencies, and the client is async by default).
Sorry @U04V70XH6 if it’s frowned upon to ask in multiple channels! I figured I would re-ask in this channel because you said a while ago something about how people are more open to questions here because that’s what they sign up for in this channel
Okay I’ll try the HTTP stuff
My context of use is that I’m working on a research project where we have a ton of markdown notes and a ton of papers. Zotero lets me attach metadata to those papers automatically and intentionally and stores all of that in a database. I wanted to see if there was some way to programmatically work with all of that data from Clojure since I know there is an extensive developer community for Zotero in general.
Btw Sean the stuff you were helping me with yesterday with the regex is helping me write a custom search engine for my MD notes :)
Zotero will be able to export csvs or JSON I’m assuming. It’s a very helpful tool which I too used to use when I was doing my research.
Oh! Thanks for pointing that out. Looking into it more, seems like I can also do RDF, which means I should be able to write datalog queries on it I think! https://www.zotero.org/support/dev/data_formats
Any suggestions for an idiomatic solution to "splice" into a vector when it's not macro-time?
;; I'm trying to write a function that behaves like this:
(defn dl [_ & args] 'todo)
(dl "Static" "Normal document flow" "Relative" "...")
#_ => [:dl
[:dt "Static"] [:dd "Normal document flow"]
[:dt "Relative"] [:dd "..."]]
;; I figure I could use mapcat, but then I'd have to go via sequences. Perhaps
;; there's an idiom for this?
I came up with this:
(defn dl [_ & args]
(into [:dl]
(mapcat (fn [[dt dd]]
(list
[:dt dt]
[:dd dd]))
(partition 2 args))))
, but it seems a bit obscure. Comments welcome.I looked at the implementation if hash-map
in clojure.core, but it just calls into Java.
I would probably do something like:
(defn dl [ & args]
(into [:dl]
(map-indexed (fn [i s]
[(if (even? i)
:dt
:dd) s]))
args))
I agree with @U7RJTCH6J, if you’re set on using positional semantics then dispatching on even?
is the thing you want
although I feel like your function is fine as well. It conveys what you’re doing more structuraly
Though dispatching on even could leave a [:dt "definition term"]
that doesn't have a corresponding [:dd "definition"]
I need positional semantics. I'm making a <dl><dt>term</dt><dd>definition</dd>...</dl>
HTML definition list.
Otherwise I'd agree that a map would be a better representation 🙂
<dl>
is a weird html element anyways. I dislike that it’s flattened and I almost always wrap the dt
dd
pairs into a div or something. for example if you style it later you very likely want them wrapped.
> but I dislike the signature, what it describes is a key value thing
Are you referring to the [_ & args]
part?
I don't like that either, it doesn't convey any intent.
pass a map and then map over it. you’ll get map entries that you can apply to the pairs
This is where my use case gets unusual. I'm writing plain HTML in EDN files; experimenting with ways to create my own "components".
Here's the EDN: https://github.com/teodorlu/subcons.teod.eu/blob/master/css-position/index.edn#L14
Here's the dl
function: https://github.com/teodorlu/subcons.teod.eu/blob/master/src/teod/subcons/transform.clj#L14
put a nil in front then or sth, but generally I would say you pass a map into a dl component, or a list of entries. thinking about where the data comes from.
to run clojure code from clj... how do you define the entry point function? So far I've got clj -X script/<filename>.clj
... This is for clj only ... not Lein or boot.
with -m
you can specify a namespace, it expects a function called -main
in that namespace
or you can skip the -X
and it will simply load the file you specify
(assuming that file has some side effects on load)
so -main ... does it needs to be specified in the clj file or on deps.edn?
the function needs to be called -main
and take any number of string arguments, when clojure is provided with a namespace to execute it will call the function called -main
with the args (and complain if the namespace doesn't have any function by that name)
I am trying to parse this json using clojure/data.json — just want some help or confirmation on idiomatic way of doing it. Sample json input at pastebin • reading the json data using -> (thread first macro) , what if one of the key is missing (how to handle that gracefullly?) • to filter out all the users email whose role is non-admin? https://pastebin.com/ELB9WCkD
(filter get-non-admin-role-user (-> "/tmp/outjson.json"
slurp
json/read-json
:data
:users
:output))
as roles is an array of map - that is causing some trouble if need to check for 2 different roles at same time.
Thanks @U8QBZBHGD for the detailed response. It is helpful. Yes, even i am also breaking my function (but little differently). ‘let’ destructring and ‘some’ looks neat.
I'm just getting my feed wet with macros and fail with a very simple one.
(defmacro testmacro [xs]
`(let [~(mapv symbol xs) ~xs]
~@(for [x xs]
`(println ~(symbol x)))))
macroexpands to (let [[foo bar] [:foo :bar]] (println foo) (println bar))
and works as I want. but when I pass the macro a var like:
(let [input [:foo :bar]]
(testmacro input))
I get an error: Don't know how to create ISeq from: clojure.lang.Symbol
Ah so, macros operate on the code itself, not on the runtime values. This macro will only work with the literal values [:foo :bar]
. Otherwise it just sees input
, which it can’t destructure - because it’s a symbol. Does that make sense?
I think I kinda know what you're saying but it's still confusing 😄 How can I make it work that it works with [:foo :bar] as argument and with a variable.. I feel like I'm making some simple very basic mistake.
I don’t think you can. You would use a function instead.
What’s the bigger picture of what you’re trying to do?
think of macros as something that can look at the code and transform it into other code
you rarely need them for most things
I use jackdaw for a kafka streams app. And I want a configurable amount of output topics but kafka streams (at least the version jackdaw is using) can't dynamically at runtime branch the input topic to multiple output topics. So I wanted to write a macro that reads the config and instead of the println
in the testmacro it would be jackdaw/branch and jackdaw/to functions.
@UFAP0C8KU Not sure if you got this sorted, but I don't think you need a macro to get jackdaw to send to multiple branches defined by some config. The jackdaw branch function takes a list of functions to decide how to branch and returns a list of streams. Doing something like this would let you dynamically branch but you'd need to do something with each of the returned streams. Like maybe send them all to a topic named in the config or something? (require '[jackdaw.streams :as k])
(defn branch-with [p]
(fn [[_ {:keys [pet]}]]
(= p pet)))
(let [config {:branches ["dog" "cat" "fish"]}
list-of-streams (k/branch source-stream (map branch-with (:branches config)))]
list-of-streams)
Does that make sense?@U0P0TMEFJ thanks for the reply.
All I want is to split the stream by some value like in your example and then output them to their own topic (in your example (k/to dog-stream (:topic-config dog))
etc)
Somehow I thought a macro would be the easiest way. But now I think just use functions is probably better. I think I was confused because I had in my mind that I have to specify the k/to
before I start the streams app, but now I realise I can just do that in my topology-builder function.
Yeah. I think that's part of the design of the Kafka streams API, and why you build a topology. In general it's best to avoid macros as much as you can. Sometimes you need them, but once you're in macroland it's really hard to escape it again ;)
is the config known at compile time?
so as long as you know the config before you define the macro you can do something like this
(def config
{:thing-1
{:a 1 :b 2}
:thing-2
{:a 2 :b 3}})
(defmacro foo
[k]
(let [thing-config (get config k)
{:keys [a b]} thing-config]
(cond (= a 1)
`[:= :a 1]
(= a 2)
`[:= :a 2])))
(foo :thing-2)
;; => [:= :a 2]
but if the system has to start up etc, I’m not sure how you’d do it. Probably is a way, but it might get messy.
Thanks for the help. I think I understand it a bit more now. I'll play around some more and see if I can make it work (or find a way to make it work at runtime with a normal fn) 🙏
Hi,
I'm wondering how to count characters in a string, just like some_str.count(char)
in Python.
And I come up with this:
(defn count-char
"Count how many char in str"
[str char]
(reduce #(if (= char %2)
(+ %1 1)
%1) 0 str))
Am I doing this right?(count "a string with characters")
is what i would do. I have no idea how this handles more esoteric unicode points and emoji though. Not sure what your requirements are or if number of characters is even well-defined right now
oh i totally misread that count. i'd probably do (get (frequencies your-string) \the-character)
(get (frequencies "characters are contained") \c)
would return 3
for the three c
s in that string
Yeah, the .count()
in Python means to count the number a specific character in that string.
strings are indexed by position to character in an obvious fashion. And getting a character by index doesn't seem to help your case here
wait, what do you mean "why can it be applied to a string"? I'm not using get
on a string in the code i gave you
(get (frequencies "characters are contained") \c)
is called get
on the map returned by (frequencies your-string)
. Check out (doc frequencies)
to see what that returns.
you can also omit get
as frequencies
returns map, which can itself be used as a function. Also you might want to add a default value of 0 to be used instead of nil
, otherwise you'd get nil for characters which are not present
user=> ((frequencies "characters are contained") \c 0)
3
user=> ((frequencies "characters are contained") \w 0)
0
Like many things in Clojure, get
is defined over an abstraction. Anything that implements ILookup
can be get
-ed.
I’m new to clojure — and I’m wondering how frequently folks find the need to use more than one major.minor version of Clojure (0.9, 1.0, 1.1, etc.) for different projects. Do you find that most of your projects use the same version? If you have existing projects using legacy releases of Clojure, do you start new projects in a newer release? Or just tend to stick to one release across the board?
something that is somewhat different about the clojure ecosystem is the version of clojure used tends to be treated like just another library
so the clojure version is listed in your project dependencies along with the other libraries and their versions you use
That makes sense — it seems like lein
, et al, take care of pulling the dependent version as if it were a library
the versions are very stable going forward. i think there were a few things added in 1.9 alpha that ended up not in a release but i upgrade clojure versions when they come out and have a strong degree of confidence that nothing bad will happen
@dpsutton — does that “upgrade as releases are available” apply to both existing code bases and new projects? So you’re, essentially, always on the latest release?
if you are familiar with maven, clojure is just another jar in your local maven repo
(that is personal projects, at work we often even deploy alpha clojure releases to production)
If you aren’t aggressively upgrading to new releases of clojure, is it fair to assume your other dependencies are the forcing function in most cases?
I avoid dependencies if at all possible largely for this reason (who has the time to keep up with all that)
I once had a dependency where I couldn't move to a newer version of clojure (there were some big changes around clojure 1.2, and the library was unmaintained)
I would say most clojure libraries are pretty tolerant in the version of clojure they work with
i'm not very familiar with the zipper library. can i use it to carry arbitrary context with me as i traverse the tree? and use that context to inform the per-node replacement logic?
you can think of a zipper as a sort of iterator, a cursor over a tree, that you can navigate around in the tree, and do operations on to edit the tree, which is trivial for a mutable tree, but a zipper lets you do it on an immutable tree
i see, thank you
can i use the zipper library to build up context as i iterate from node to node, so that the changes i made in a previous node can inform future changes? or should i do that with an atom? or with a loop / reduce?
but basically yes, when you use a zipper you don't have access to the whole datastructure, you are basically building a recipe for rebuilding the tree as you descend into it, and rebuilding as you climb out of it
when I say a zipper is like an iterator, it very much is, when you use an iterator the looping and actual traversing is provided by you, and is not part of the iterator, the same is true of zippers
i'm reading http://www.exampler.com/blog/2010/09/01/editing-trees-in-clojure-with-clojurezip/
you may also be interested in something like https://github.com/redplanetlabs/specter
yes, specter
our team is a bit skittish
cautious, really. not skittish.
I think that's wise
but this is the problem that specter is aimed at solving and it does pretty well.
with clojure.zip
, I usually use zip/next
rather than the left,right, up, down
I've never used specter or zippers in a real code base, I think because I always prefer to take trees, normalize them into some relational form, and do whatever I want there, and then re-generate the tree if needed
zip/next
instead of left right up down because you want to traverse the whole tree, not just certain nodes you know the exact locations of?
right exactly
typically, it's because I'm working with a tree and I want to write a transformation recursively
eg.
(defn gen-table-of-contents [doc]
(loop [zip (doc->zip doc)
toc (make-toc)]
(if (z/end? zip)
(z/root toc)
(let [node (z/node zip)]
(if (instance? com.vladsch.flexmark.ast.Heading node)
(recur (z/next zip) (add-section toc node))
(recur (z/next zip) toc))))))
right, if it's a simple transformation, then clojure.walk
can work, but zippers can be more flexible and you can collect information without side effects
i've had good results with clojure.walk
in the past. i gather the zipper lib is for more difficult...
you'd be surprised what you can achieve with clojure.walk smuggling data up and down attached as metadata
interesting...
the other benefit of clojure.zip
is that it can work on trees that have different shapes. Like you can make a zipper for hiccup data or even Java classes like in my gen-table-of-contents
example
I've also used clojure.zip
for editing ASTs where the branches are found in a specific place (eg. :children
)
I was working with a non-clojure AST