This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-14
Channels
- # announcements (13)
- # aws (2)
- # babashka (17)
- # beginners (80)
- # biff (10)
- # cljs-dev (51)
- # cljsrn (6)
- # clojure (42)
- # clojure-australia (9)
- # clojure-boston (2)
- # clojure-europe (17)
- # clojure-sweden (3)
- # clojure-uk (53)
- # clojurescript (44)
- # code-reviews (2)
- # core-async (5)
- # cryogen (3)
- # cursive (32)
- # datahike (1)
- # datomic (11)
- # events (1)
- # fulcro (22)
- # helix (3)
- # honeysql (3)
- # leiningen (4)
- # lsp (30)
- # luminus (13)
- # malli (5)
- # off-topic (115)
- # other-languages (5)
- # pathom (10)
- # polylith (23)
- # re-frame (24)
- # reagent (10)
- # releases (2)
- # shadow-cljs (124)
I've got a couple of related functions in a file that I'd like to be able to call directly from the command line. What's the recommended way of doing that? Would it just be to parse some command line options and call the appropriate function from -main
?
If so, are there any Clojure libraries similar to https://github.com/google/python-fire or https://click.palletsprojects.com/en/8.0.x/ in Python, for quickly putting together simple CLIs?
@kiran.joshi just in case you're writing command line scripts and you're not aware of https://babashka.org/, I suggest you check it out. Otherwise, sorry for the spam and carry on. :)
@kiran.joshi If you use Clojure CLI, the -X
exec option should be what your looking for.
For your second question AFAIK:
• https://github.com/clojure/tools.cli
• https://github.com/l3nz/cli-matic
How do Datalog and Specter queries compare? I don’t fully understand why I would use one or the other.
Datalog is a query language similar to GraphQL and Specter is used to conveniently run up and down nested data structures using keywords specific to specter
I guess my question then would be: when is it more useful to run a datalog query and when should I run a specter query?
I guess Specter might just be more precise? Like I know exactly what I’m looking for and where it is, since I need to manually specify all elements of the tree. But datalog helps me find things without looking at the tree?
In other words, I get to skip a few steps I would have needed to take in Specter
Hello everyone, I'm trying to convert a list of maps into eav-triplets. There is one catch: some values are in a vector, and they need to get unwrapped. This is my current solution:
(defn map->eav
([data]
(let [ids (atom 0)]
(map->eav data (fn [] (swap! ids inc)))))
([data id-gen]
(->> data
(mapcat
(fn [e]
(let [id (id-gen)]
(for [[k v] e]
[id k v]))))
(reduce
(fn [acc [e a v]]
(if (vector? v)
(into acc (for [n v] [e a n]))
(conj acc [e a v])))
[]))))
(map->eav [{:list ["a" "b" "c"]}])
;; => [[9984 :list "a"] [9984 :list "b"] [9984 :list "c"]]
This works, but I wonder if there isn't a more concise solution to the problem?Well don’t call RT.nextID - that’s implementation stuff you shouldn’t use directly
(def id-gen
(let [a (AtomicLong. 1)]
(fn [] (.getAndIncrement a))))
=> #'user/id-gen
(id-gen)
=> 1
(id-gen)
=> 2
or use UUID
good morning. When using java interop, im having difficulty invoking the correct overloaded function based on parameter type.
(. java.nio.file.Paths (get "/tmp"))
=> ; Execution error (ClassCastException) at eventflow.ingress.file/eval11660 (form-init15515817518546427981.clj:62).
; class java.lang.String cannot be cast to class java.net.URI (java.lang.String and java.net.URI are in module java.base of loader 'bootstrap')
(class "/tmp")
=> java.lang.String
it sure reads as if it's invoking the static method accepting a URI, not a string
(java.nio.file.Paths/get "/tmp" (make-array String 0))
should work for you. There is no signature that is (String)
. it's (String, ...String)
thanks, will give that a try
https://clojure.org/reference/java_interop#_arrays check out the varargs section
Which clojure function could I use to run a function on each element in a collection?
I'm working in core.logic and I'm trying to check a collection of things being in another collection. For example, checking if each individual element in the collection [:one :two] is in [:one :two :three]
The current line looks something like this, however everyg won't work because in
isn't a collection of lvars (I think), it's something like [:one :two]
(everyg #(membero % state) in))
you can maybe try something like:
(defn for-all [goal lst]
(l/conde
[(l/== lst ())]
[(l/fresh [fst rst]
(l/conso fst rst lst)
(goal fst)
(for-all goal rst))]))
(for-all #(membero % state) in)
What would be the idiomatic way to do the equivalent of this in clojure
private Either<Error, Output> Parse(string input) { ; either return an Output or an Error }
Parse(someInput).Match(left: ProcessError,
right: ProcessOutput)
Return a map, something like
{:errors []
:output []}
then check if errors
is empty or nil
? And if its not errors
trumps output and deal with them, else deal with the output ?ANy libraries that support stuff like
Foo().Then(Bar).Then(Quax).Match(left: ProcessErrors, right: ProcessFinalResult)
That will fail quick into ProcessErrors if any of Foo, Bar or Quax return the equivalent to a Left EitherI do it lots in data processing pipelines, but it is such a small thing to implement I tend to just write it as needed
there are people that do that (and there are some libraries in this vein)
Clojure leans on exceptions for error reporting and that's what I consider idiomatic
For more context, I was trying to extend a story generator from a core.logic tutorial I found to accept multiple inputs as well as multiple outputs per action, the entire function looks like this
;;function to find an action that can be used, consume the elements in the state, and produce new story state
(defn actiono [state new-state action]
`(fresh [in out temp]`
`;;one branch for multi input, the other for a single input.`
`(conda`
`[(all`
`(== (coll? in) true)`
`(everyg #(membero % state) in))`
`(ploto in out)`
`(everyg #(rembero % state temp) in)]`
`[(all`
`(membero in state))`
`(ploto in out)`
`(rembero in state temp)]`
`)`
`(appendo out temp new-state) ;;add the elements to the new state`
`(== action [in out])))`
I'm quite new to this so it'll take me some time to go through you little code block hiredman so I can know what it does, but thank you.
the way core.logic is written as a dsl (and minikaren which it is based on) lets you freely mix clojure and core.logic code, but they are distinct languages, clojure is kind of the meta language for core.logic. So you can't really throw clojure code like coll?
into core.logic and have it work, but you can use clojure code to generate core.logic
Alright I think that makes sense because in is created as an lvar. I got confused because the input that I'm trying to extend it for is collection
everyg is an example of this, it is actually kind of regular clojure code, it can't handle lvars, but it generates a core.logic goal
Yeah I will be careful about when I use clojure functions while writing core.logic. I'll try to rethink that block and see what I can come up with
anecdotally, there certainly are clojure devs that downplay the importance or usefulness of unit tests. i think there's some merit to the idea that the repl gets you much of what a unit test would get you (at least at dev time). i think this gets complicated by the fact that as a dynamic language, clojure code bases stand to benefit /more/ from unit tests
Based on our code base at work, I’d say we value unit tests:
Clojure build/config 20 files 233 total loc,
45 deps.edn files, 774 loc.
Clojure source 355 files 89158 total loc,
3551 fns, 925 of which are private,
569 vars, 30 macros, 90 atoms,
85 agents, 24 protocols, 67 records,
857 specs, 33 function specs.
Clojure tests 378 files 23747 total loc,
4 specs, 1 function specs.
What tool did you use to generate this report?
I tend to develop tests initially via REPL interactions, starting with a Rich Comment Form (RCF — (comment ..)
) as I explore a problem space and evolve a solution and the code in the comment
gets refactored out into source functions and tests for those functions.
(and, to be clear, I do not type into a REPL: I always edit code in a file and eval expressions into the REPL running in the background)
Iike that method…I do something similar where I start a test file and put the function right above the test and build the function as I write tests with the REPL going. very similar to me TDDish flow in other languages
I figured the core team values them but I know lots of the devs that use Clojure in the wild seem to be more startupy, full stack apps. Closer the Ruby/Rails startup stuff where I’ve seen fewer tests and more write lots a code, deploy and fix issues found on the fly. Not being necessarily critical of this method as I’m sure in some environments getting slightly buggy code out the door that you fix quickly might be more valuable than spending more time writing tests and exercising a more extensive software engineering disciplined approach.
I have more interest in working on larger systems that have to work and perform well. Deploying a bug is bad. Deploying slow code is bad. I probably end up writing more test code than actual code. But also realize tests are code that need maintanence so they should be well written. But having some extra tests you don’t need is much easier to remedy (delete them) than missing tests that you DO need.
How does the compiler keep atoms from being corrupted, knowing that at the beginning it could change the order of execution of things and now not exactly?
Well atoms are mutable, how an atom does not get corrupted, since these are mutable, what process should the compiler follow
@jimmyssj3 Just checking, have you read this? https://clojure.org/reference/atoms
Atoms are operated on via swap!
(mostly) and reset!
(occasionally), and those functions ensure that the semantics are retained by design.
@jimmyssj3 Atom is implemented in such a way that JVM ensures that any successful write will be seen by any subsequent reads in other threads. Lock-free update mechanics are possible because of CAS, compare and swap. 1. Thread reads "current value" of the atom as a "last known" 2. Runs a function to produce a "new value" 3. Tries to swap "current value" by the "new value" 4. If "current value" equals to "last known" value, "new value" is written, else, another thread was faster to update the value and current thread should retry the whole process. (Hence no side-effects requirement for a "new value" function)
Here is an example of 100 threads doing 10k increments each to the integer stored in the atom.
(defn test-atom [nthreads niters]
(let [ref (atom 0)
pool (Executors/newFixedThreadPool nthreads)
tasks (repeat nthreads #(dotimes [_ niters]
(swap! ref inc)))]
(doto pool
(.invokeAll tasks)
(.shutdown)
(.awaitTermination 60 TimeUnit/SECONDS))
@ref))
=> #'user/test-atom
(test-atom 100 10000)
=> 1000000
You may wan't to dig deeper into JVM memory model to understand the foundation clojure is built on, but that isn't strictly necessary. https://shipilev.net/blog/2014/jmm-pragmatics/
https://www.youtube.com/watch?v=ScEPu1cs4l0 is good background
if you are familiar with java, the source of swap!
might be revealing as well. it's an infinite loop, get the value before, apply the function, compare and set. it the compare and set was successful, done, otherwise loop.
are there any good guides on starting a simple clojurescript project that doesn’t need the browser (eg a library of functions). i know i can use node. but i cant seem figure out what my deps.edn should look like, what the command line is to open a repl and play with my code, and what the command line is to run my tests.
clj -M --main cljs.main --compile foo.core --repl
works fine to open a repl connected to a browser and im able to run my code
but when i try clj -M --main cljs.main --repl-env node --compile foo.core --repl
the repl loads (without the browser) but i can’t run my code.
`Execution error (ReferenceError) at (<cljs repl>:1).
foo is not defined`
Maybe ask in #clojurescript
i also wonder if the answer is “if you’re not using the browser, just use clojure”…
Hah that is definitely an answer. You could write everything in cljc and use the Clojure repl, provided you don’t need any features of node (fs, event emitter etc)
yeah i don’t need any of that
@U021TB0SSA2 Something worth bearing in mind is that ClojureScript has to go through a compile-to-JS phase, which requires the ClojureScript compiler which is running on the JVM anyway. So if you don’t need a browser and you don’t need Node.js features, I would probably just write it as .cljc
files, run it on the JVM as Clojure while you’re developing stuff, and use Olical’s cljs-test-runner
to make sure it compiles and runs as ClojureScript. That’s what I do for HoneySQL (on the v2 branch).
thank you - i’ll look into cljs-test-runner!
I saw this the other day https://github.com/raspasov/cljs-101
yeah - was shared in another thread i started in #clojurescript - i found clj -M -m cljs.main --repl --repl-env node
also works.