So like in your main thread, you could check if the future is realized? yet, and if it is, check if it errored and do whatever you want in that case.
But in your case, probably just have a try/catch inside the future itself.
Is there a way to provide a docstring to a clojure function defined in terms of def
instead of defn
?
I have some functions that could benefit from the point-free style but I don't see a way to add metadata or a docstring
def takes an optional doc string argument, and metadata can be provided on the symbol itself
(ins)user=> (def ^{:foo [1 2 3]} f "takes no args and returns nil" (fn f []))
#'user/f
(ins)user=> (doc f)
-------------------------
user/f
takes no args and returns nil
nil
(ins)user=> (meta #'f)
{:foo [1 2 3], :line 1, :column 1, :file "NO_SOURCE_PATH", :doc "takes no args and returns nil", :name f, :ns #object[clojure.lang.Namespace 0x6f012914 "user"]}
user=>
right, I have a try/catch in the future
but I start to feel like I'm using futures incorrectly, and should be using another multithreading technique more appropriate
Ahh I see
@luishendrix92 you can type (doc def)
and see more
thanks
I can't speak to that, but it's fine to use futures to fire async tasks that only do a side effect. Just make sure you try/catch them.
(future
(try (task)
(catch Throwable t
(handle-error t))))
You can make yourself a little util for it:
(defn fire-async
[task error-handler]
(future
(try (task)
(catch Throwable t
(error-handler t)))))
With future, you can fire an infinite number of concurrent tasks. There will be one thread per concurrent task. So at 100 concurrent tasks, you will have 100 threads. As the number of concurrent tasks goes down, the number of threads will go down as well, but it will lag behind, as threads wait for 60 seconds in the hope they can be reused.
This means that in theory, you could run out of memory if you fire too many concurrent tasks. And really, it will be the total set of concurrent futures and agent send-off executing in your program.
That's why sometimes people will recommend in server code where you can't predict how much concurrency you'll end up having (nothing upstream of the future call is bounded for example), to either use your own executor service. Or to change the default executor for future to a bounded one, or to use core.async with bounds.
It’s true for many Common Lisp libraries as well.
@dorab i have leiningen installed and working. Lein repl and cider repl in emacs also working. I am basically trough chapter2 of brave. And was able to create simple stuff like enigma decription in repl etc. Rly only simple stuff. But still not sure where to go from there
@vincenz.chianese thank you for your advise i have the feeling brave is more like a reference book which is also good to have in the beginning, but yah i will take a look into the video.
How can I load code created by another JVM language? Does it suffice to ask the other language to produce a .jar file? Can I load the .jar file explicitly in clojure? Or is it more complicated than that? E.g., does it have to be installed into some mutually agreed directory with a bunch of boiler plating surrounding it? I'd prefer to have something light which I can later just delete with no lasting side effects.
clojure usually (unless you encode how and what to compile using system tools) have no idea how to compile another PL so to use libs written for JVM but in another language (eg. scala) it should be provided as compiled jar
there are some options to load jar file, all depends on how you run your application:
1. if you run using java
command — add this jar to classpath (`-cp` option)
2. if you running application using clojure cli (aka. tools.deps) — you can add dependency pointing to that jar (`{:deps {some/id {:local/root "/path/to/file.jar"}}}`). in that case jar file can be placed anywhere
3. you can “install” that jar into local maven repository (usually $HOME/.m2/repository/…
)
I’m sure this is answered already; when I add more require statements in for example core.clj, and in project.clj, what steps do I have to take in Emacs/Cider environment to get the editor pick that up? cider-restart doesn’t seem to be enough, I have to shut down the whole cider/nrepl process it seems.
Oh, I’ve done lein deps to download the deps as well.
Currently i'm running clojure in two different ways. from the lein command line either via "lein test" or "lein repl", and also running from cider within emacs. At the moment, I'm not interested in installing applications based on .jars coming from different JVM langauges, rather I'm just interested in using the clojure reflection (`clojure.reflect/type-reflect`) capabilities to examine classes which were created elsewhere. elsewhere being directly from java or from Scala.
running lein repl
or start repl from emacs should be enough but will require restart of the repl in case you add dependencies in project.clj
So in these cases would it suffice just to persuade java or Scala to create a single .jar file?
For example. I'd like to use clojure.reflect
to examine the classes produced by the following scala code.
trait A {
def foo(s: String): AnyRef
}
trait B {
def foo(s: String): String
}
class Foo extends A with B {
override def foo(s: String): String = s
}
Yeah okay. Thanks 🙂
I can’t say much about scala workflow, specifically about the content of produced jar file. but it should be sufficient if at the end this jar file will have a bunch of .class files which can be loaded in clojure for analysis
so is the .jar a sort of tar file of .class files? Can I put the .jar in /tmp/erase-me-tomorrow/file.jar
and then somehow tell lein to load it so that the classes are available at the clojure repl??
or is it the case that the .jar file might actually be any of many many different things depending on the language which produced it?
JAR (or JavaARchive) is just a package file format. there are no restrictions to file types it contains. Typically it contains many java .class files optionally together with source file used to produce those .class’es so in general .jar file might contain anything depending on PL
for instance — I saw jar files produced by javascript with resources meant to be used in java application
https://cljsjs.github.io/ like here
jdk also providing a tool to examine content of jar files
jar tf /path/to/file.jar
(answering on the question about leiningen)
if I’m not mistaken — to add local jar via leiningen you should use :resource-paths ["/path/to/local.jar" …]
path can be absolute or relative to project’s root
Hello! :3 Would someone be willing to help me out with an exercise I'm doing? It's a transcription of DNA to RNA and this is what I came up with:
(ns rna-transcription)
(defn- valid? [dna]
(nil? (re-find #"[^CGTA]" dna)))
(defn to-rna [dna]
(let [modify-letters (map {\G "C" \C "G" \T "A" \A "U"} dna)]
(assert (valid? dna))
(apply str modify-letters)))
However, I was asked for further edits/optimalisation to avoid nil?
(done), to do validation based on count
(done) and (what I'm struggling with) to exchange map
for keep
(filters nil automatically and I don't iterate over the string again).
(ns rna-transcription)
(defn- valid? [dna, rna]
(= (count dna) (count rna)) true)
(defn to-rna [dna]
(let [rna (keep #{\G "C", \C "G", \T "A", \A "U"} dna)]
(assert (valid? dna rna))))
I don't understand how to use keep
instead of mapping for transcription though. :/
Thank you in advance!thank you very much
just change #{\G "C", \C "G", \T "A", \A "U"}
to
{\G \C, \C \G, \T \A, \A \U}
a map is a function of key in clojure
but #{
is a set literal - https://www.clojure.org/guides/learn/syntax#_literal_collections
Thank you! I was getting a bit desperate and trying out everything. 😅 This still fails tests though.
lein test :only rna-transcription-test/it-transcribes-all-nucleotides
FAIL in (it-transcribes-all-nucleotides) (rna_transcription_test.clj:18)
expected: (= "UGCACCAGAAUU" (rna-transcription/to-rna "ACGTGGTCTTAA"))
actual: (not (= "UGCACCAGAAUU" nil))
lein test :only rna-transcription-test/transcribes-cytosine-to-guanine
FAIL in (transcribes-cytosine-to-guanine) (rna_transcription_test.clj:6)
expected: (= "G" (rna-transcription/to-rna "C"))
actual: (not (= "G" nil))
right, you have (assert …
expression inside of let
this is not really clear from the docstring but assert returns nil in case underlying expression resulting to trythy value
(defn to-rna [dna]
(let [rna (keep {\G \C, \C \G, \T \A, \A \U} dna)]
(or (assert (valid? dna rna)) rna)))
there is one of a few “valid” changes to do what you want
or you can be a little bit more explicit and use if
here
(if (valid? dna rna) rna (throw (ex-info "Invalid DNA sequence" {}))
1❤️Works like a charm, thank you!
anyone know if cider has a way to specify a fn to run on jack in ? I see a lot of people creating startup shutdown reload fn's so I am guessing no but it would be nice to jack in and have the startup fn executed instead of typing it each time
keep
is a nice approach, thanks.
I just used a map
with an anonymous function to wrap the or
around the hash-map, which is used as a function over each character in the dna string.
If the character is not found, then throw the error.
(defn to-rna
[dna]
(string/join
(map #(or (dna-nucleotide->rna-nucleotide %)
(throw (AssertionError. "Unknown nucleotide")))
dna )))
with the hash-map to define the transformation as a simple dictionary
(def dna-nucleotide->rna-nucleotide
"DNA to RNA transcription mappings"
{\G \C
\C \G
\T \A
\A \U})
1❤️is my understanding correct that I cannot use {:pre ... :post ....}
within a defmethod?
@oliver.marks functions can be called when starting a REPL (regardless of how they are started) https://practicalli.github.io/clojure/clojure-tools/projects/configure-repl-startup.html
actually, with core.async, I could probably create a ~10 channels that work concurrently, with extra work waiting in the queue
and when my program exits, I could ensure they are all done with alts!
which is neat (I wondered how I could do that)
I will play around with that
oh that makes sense just call it in the file, so if i create user.clj and make that the namespace and call the startup there at the top level, I was over complicating it in my head 🙂
@oliver.marks there are cider specific variables for restarting the repl via cider which builds upon that approach https://practicalli.github.io/spacemacs/clojure-repl/component-lifecycle.html
awesome thanks for the links @jr0cket
I was aware of integrant never realised it had hooks into cider that will be super handy and gives me a reason to use that library now 🙂
Is there a way to give a set of keywords the same spec, without having to specify each one like this:
(s/def ::foo fancy-spec)
(s/def ::bar fancy-spec)
(s/def ::baz fancy-spec)
I'm working through The Little Schemer in Clojure and have arrived at the last chapter. It uses data types from Scheme for the examples and I'm not sure how to approach it from Clojure. Anyone happen to have done it before? They define two functions that rely on Scheme's *const
, *quote
, *identifier
, *lambda
, *cond
, and *application
and then build upon that in later problems:
(define atom-to-action
(lambda (e)
(cond
((number? e) *const)
((eq? e #t) *const)
((eq? e #f) *const)
((eq? e (quote cons)) *const)
((eq? e (quote car)) *const)
((eq? e (quote cdr)) *const)
((eq? e (quote null?)) *const)
((eq? e (quote eq?)) *const)
((eq? e (quote atom?)) *const)
((eq? e (quote zero?)) *const)
((eq? e (quote add1)) *const)
((eq? e (quote sub1)) *const)
((eq? e (quote number?)) *const)
(else *identifier))))
(define list-to-action
(lambda (e)
(cond
((atom? (car e))
(cond
((eq? (car e) (quote quote))
*quote)
((eq? (car e) (quote lambda})
*lambda)
((eq? (car e) (quote cond))
*cond)
(else *application)))
(else *application))))
https://pdfs.semanticscholar.org/35d0/d5275a8390c351ce98fbdc2ad37d210ba63b.pdf page 181I havent had chance to create an integrant example, but it should work just like mount (with slightly different libraries)
You can s/def one keyword to another
You can, place it after arglist definition
(defmethod foo :dispatch-value [& args] {:pre pre-fn :post post-fn} …)
user=> (defmulti adder :k)
#'user/adder
user=> (defmethod adder :y [{:keys [y]}] {:post [(pos? %)]} (inc y))
#object[clojure.lang.MultiFn 0x5286c33a "clojure.lang.MultiFn@5286c33a"]
user=> (adder {:k :y :y 1})
2
user=> (adder {:k :y :y -2})
Execution error (AssertionError) at user/eval140$fn (REPL:1).
Assert failed: (pos? %)
1is that what fn-tail means in the https://clojuredocs.org/clojure.core/defmethod?
yes, more precisely — https://github.com/clojure/clojure/blob/clojure-1.10.1/src/clj/clojure/core.clj#L1787
have a look at how defmethod is implemented
(fn & fn-tail)
so fn-tail can have everything that can take fn
like a function name to produce better error stack traces
or extra metadata
etc.
How can I create a project with Clojure (Clj) with some template mechanism to have the directory structure like that produced by lein new app
but using deps.edn? I tried the following:
clojure -M -m myname.sandbox
with @seancorfield’s clj-new aliases, but the directory structure is sandbox/src/myname/sandbox.clj,
but I need it to be sandbox/src/sandbox/core.clj
I wonder if I could just use lein new app sandbox
and add deps.edn by manually translating project.clj to deps.edn, I wonder if it would work to use clj for execution and continuous tests. I tried the following. It did run with project.clj:
clojure -M -m sandbox.core
I doubt I can answer your question, but I'm missing what "doesn't work" means - error? different structure than expected? if so, what structure?
Thanks! Is it possible to do it in bulk? Say I have 20 keywords that I all want s/def
'd to the same spec, and don't want to repeat myself for 20 lines 🙂
not part of spec, but macros exist :)
Understood -- thanks!
@alexmiller yes, it's different structure. I've improved my question. Thanks!
@thomasfuston So I probably misunderstood your question. I thought you were having problems writing something simple. So, I presumed it was because your setup was not complete. It now sounds like you have the setup just fine, and are looking for what to do next. In that vein, what @vincenz.chianese says is good advice. If you're not already experienced in functional programming, then writing functions that can be composed together is a good next step. Previous expose to OOP can be detrimental since it causes you to un-learn some habits in order to do good FP. Most of my programming is just functions which I just call from the REPL. The only time I ever make a stand-alone command-line program out of the function is when I need the function to be run by someone else who is not familiar with a REPL and does not want to learn about the REPL. If you have not already, you could try reading/watching articles/videos about REPL-driven-development. You can start at https://clojure.org/guides/repl/introduction and https://clojure.org/guides/repl/annex_community_resources for other resources. FP/REPL are sometimes harder to learn because of previous exposure to OOP. But, once you persevere and get to the ah-ha moment, you will be changed! If I'm telling you things you already know, you can ignore me 🙂
you may want to checkout the last paragraph in https://github.com/seancorfield/clj-new#getting-started
@hiredman Thanks for the pointer. With minor variation, the following achieves the structure that I want:
clj -X:new-app :name sandbox.core
@yubrshen foo.core
is a bit of an anti-pattern -- the only reason .core
is prevalent in Clojure is because Leiningen added it to single-segment names as a default to avoid ending up with single-segment namespaces (and therefore top-level class names in JVM byte code).
That's why clj-new
strongly encourages you to pick a proper name for your project -- either <orgname>/<myproject> or <username>/<myproject> -- and the Clojure CLI also discourages libraries with the same group and artifact ID (i.e., use a proper orgname or username in both your project and your top-level namespace segment).
Even when building an application, following that "proper" naming pattern makes it less likely your own namespaces will conflict with any third party library code you use.
(the author of Leiningen is on record as regretting his decision to add .core
by default and says he should have required multi-segment names -- and lein new
will already reject a bunch of names so it's not like it isn't already opinionated 🙂 )
When your app closes, running futures will prevent it from shutting down, so it will wait for all futures to complete as well, nothing will get interupted
@yubrshen Unless a Leiningen project relies on certain plugins that inject code or config, then it should be just a matter of manually adding the right :paths
and :deps
details are in the deps.edn
file to run a project Leiningen project with Clojure CLI tools instead. I do this for http://Exercism.io and can just use {:paths ["src"]}
as the only dependency is clojure and that is pulled in from the install configuration.
You can always refactor the namepaces and file names once you have an understanding of the tutorial you are following.
Hi, how to get :as all
in the second argument?
(fn [db [_ new-filter-kw]]
(assoc db :showing new-filter-kw))
Do you mean you want a parameter named all
to be equal to the value of the entire 2nd argument, which will be a sequential data structure of some kind (e.g. list, vector, etc.) ?
If so, here is a sample REPL session showing one way:
user=> (defn foo [db [_ new-filter-kw :as x]] [db new-filter-kw x])
#'user/foo
user=> (foo 1 [2 3])
[1 3 [2 3]]
thanks, for some reason I was putting :as all
outside of the argument array.
Hi everyone! Not sure if I should post this here or on the clojurescript channel but here it goes: I'm starting learning clojurescript and I'm setting up my development environment. My dev environment is a remote box running Spacemacs, so my idea is to run the clojurescript repl in that box connected to a browser in another machine. I've tried the default "browser" repl without success (even changing the "host" to my IP instead of "localhost") I've also tried figwheel (using the "flappybird" example) but the browser tries to connect to a websocket on "localhost" again. So my question is: how do I change the host on figwheel to my host instead of always pointing to localhost? Thanks!
Thank you for the reply. I tried that but didn't work 😞 I tried :connect-url, :server-ip, :ring-server-options {:host} But none of those seem to do anything. I'm addind those to the project.clj file
I'll post it in the right channel.
Even if you call shutdown-agents
this will be the case. All running future and agent actions will need to first complete before the app terminates