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=>
Ahh I see
@luishendrix92 you can type (doc def)
and see more
thanks
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!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" {}))
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})
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
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? %)
is 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!
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 🙂 )
@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.