This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-15
Channels
- # announcements (3)
- # architecture (1)
- # babashka (52)
- # beginners (228)
- # calva (1)
- # chlorine-clover (31)
- # cider (9)
- # clj-kondo (16)
- # cljs-dev (25)
- # cljsrn (21)
- # clojure (116)
- # clojure-argentina (8)
- # clojure-europe (18)
- # clojure-france (17)
- # clojure-germany (1)
- # clojure-nl (5)
- # clojure-spec (49)
- # clojure-uk (63)
- # clojurescript (59)
- # community-development (14)
- # conjure (89)
- # core-matrix (1)
- # cursive (18)
- # data-science (1)
- # datomic (27)
- # exercism (4)
- # figwheel-main (5)
- # fulcro (38)
- # ghostwheel (8)
- # graalvm (5)
- # hoplon (2)
- # jobs-discuss (17)
- # juxt (1)
- # lambdaisland (5)
- # luminus (1)
- # lumo (9)
- # malli (7)
- # off-topic (32)
- # planck (24)
- # re-frame (14)
- # reagent (14)
- # reitit (14)
- # rum (23)
- # shadow-cljs (80)
- # spacemacs (2)
- # sql (6)
- # unrepl (1)
- # xtdb (2)
hi, I just re-discovered Clojure and I'm very excited to start learning. What resources do you recommend ? I have 10+ years coding and I'm proficient in Java and JavaScript
Thanks. Could you be more specific? I've already built a simple clojure native application with GraalVM and also started this https://github.com/ieugen/clj-ledger - using clojurephant
I would recommend you do the following: Read through https://kimh.github.io/clojure-by-example/#about 1 Then read through https://aphyr.com/posts/301-clojure-from-the-ground-up-welcome Then read through https://clojure.org/reference/reader Now start referring to the Cheatsheet https://clojure.org/api/cheatsheet and http://clojuredocs.org and http://cljdoc.org for all other things Finally, read through guides here https://clojure.org/guides/getting_started Now go to http://4clojure.org and go through the exercises, start with elementary and easy. Even better, get the Android app, so you can practice on the go, the bus, the bathroom. Also for some reason the order of exercise in the Android app is the best, so I'd try and follow that. You don't need to go through them all, you can probably stop after easy or medium. Once that's done, get Clojure Cookbook and go through the recipes. Oh and, always go to the Clojure slack beginner channel and don't hesitate to ask questions and for help. Maybe always have it open in a tab: https://clojurians.slack.com/?redir=%2Fmessages%2Fbeginners%2F
If you have the budget for a book or two, I would recommend "Programming Clojure, 3rd ed." as one: https://pragprog.com/book/shcloj3/programming-clojure-third-edition
I like Python-style string formatting, like "hello {name}".format(name=name)
. Is there a way to do something similar in Clojure? For that simple example you can just use core/str
, but for complex strings with multiple variables, where some are reused, str becomes hard to read. Same with the C-style formatting from java.
If you're looking for named args specifically, I don't think there's anything built in. You could use a templating language like Selmer for this (https://github.com/yogthos/Selmer)
But if I have lots of small strings to interpolate, it sounds like it would be slow. I should check it out though, thanks!
Also found this: https://cemerick.com/2009/12/04/string-interpolation-in-clojure/
In core, you also have https://clojuredocs.org/clojure.core/format and https://clojuredocs.org/clojure.pprint/cl-format; with the caveats that they won't work in CLJC and aren't exactly what you asked for; but definitely more powerful than just (str ...)
Yeah, format is variadic and too hard for me to get right XD Thanks for cl-format, sounds like something I should read up on.
cl-format
is a DSL beast. You may want to read up on it via some common lisp docs (e.g. http://www.gigamonkeys.com/book/a-few-format-recipes.html) and probably want to hide the line-noise DSL behind a function with good docstring of expected output. 😄
I've got two questions myself. Do I need to use Maven with clojure or can i skimp by without it? My Second questions is; I'm running CLI with tool.deps I believe and it will not let me use Ctrl+D to exit out of clojure
I'm using https://github.com/clojurephant/clojurephant - via gradle because I would like to have multi language components in there
Hm. I might give this a try later but atm I think I'll stick to what I have currently unless I set up something incorrectly. Appreciate it though
Ctrl+D should exit the deps repl, but only if there is nothing typed in the current line
hi there, does anyone know how I can generate all the dates between two LocalDate instances ? I'm trying it like this
(defn months-between
"Months between dates. Generates a sequence of java.time.LocalDate s for a given period"
[startDate endDate]
(take-while (fn [aDate] (.isBefore endDate aDate)) (iterate (.plusMonths startDate 1) startDate)))
end of course it fails
Execution error (ClassCastException) at netdava-internal-reporting.core/months-between (core.clj:4).
class java.time.LocalDate cannot be cast to class clojure.lang.IFn (java.time.LocalDate is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')
Your error says you are trying to use a LocalDate as if it were a function, and that doesn't work because LocalDate is not a function. That's because (.plusMonths startDate 1) returns a LocalDate, but iterate expects the first argument to be a function
got it, thanks
(defn months-between
"Months between dates. Generates a sequence of java.time.LocalDate s for a given period"
[startDate endDate]
(take-while (fn [aDate] (.isAfter endDate aDate)) (iterate (fn [x] (.plusMonths x 1) ) startDate)))
You can also do: (iterate #(.plusMonths % 1) startDate)
using the anonymous function literal #()
How would you recommend I get the behaviour of interleave
, but with the interwoven collection having length 1 less than the the primary collection?
I want to achieve the following:
(def grouped-thousands [34 758])
(def qualifiers ["thousand" "million" "billion" "trillion"])
(my-nifty-interleave-fn grouped-thousands qualifiers)
=> (34 "thousand" 758)
Interleave gives me this, which makes sense:
(interleave grouped-thousands qualifiers)
=> (34 "thousand" 758 "million")
you probably need 1) prepend something (`nil` ) to your qualifiers, 2) reverse
your grouped-thousands
before interleave
, 3) reverse
the result, and drop the first element of it edit: or, rather, 3) drop the first, then reverse, or something
OT: since I literally just brought up cl-format
in a different thread, I've got to mention this one liner if you're interested in just having this work (and not just "solving a puzzle").
user=> (clojure.pprint/cl-format nil "~r" 12345768)
"twelve million, three hundred forty-five thousand, seven hundred sixty-eight"
thanks, good to know. I am in it for the puzzzle...... but man my head is hurting right now lol. guess it doesn't help that I"m learning clojure after working a full day
this is an "easy" problem on http://exercism.io lol
Try with:
(-> grouped-thousands
reverse
(interleave qualifiers)
butlast
reverse)
(defn say-big-number
[num]
(let [words (->> num
grouped-thousands
(map say-hundreds))
interwoven (interleave words thousands-qualifiers)
to-english (->> interwoven
butlast
reverse
(join " "))]
to-english))
🤯 this works... (uses some other functions)You are solving "Say" on exercism, aren't you? There is an #exercism channel as well, 🙂
Hi there,
I have a question:
in the clojure repl, I can get doc by invoking doc
macro
user=> (doc pr)
-------------------------
clojure.core/pr
([] [x] [x & more])
Prints the object(s) to the output stream that is the current value
of *out*. Prints the object(s), separated by spaces if there is
more than one. By default, pr and prn print in a way that objects
can be read by the reader
nil
but I cannot use it like this:
user=> (doseq [f [pr pr-str]] (doc f))
nil
why is that? how can I change this?
doc
is a macro, and it is written in such a way that it does not evaluate its argument.
This might be close to what you want: (doseq [f '[pr pr-str]] (#'clojure.repl/print-doc (meta (resolve f))))
(source doc)
shows the source code of the doc
macro in a REPL, and the last case shows what it does if the thing you want to show the doc string for is none of the earlier special cases.
(doseq [f '[pr pr-str]] (#'clojure.repl/print-doc (meta (resolve f))))
it is magic to me, but it works
thank you!
Agreed there is some magic-like stuff there for someone new to Clojure. Happy to point you at documentation that explains what some of the pieces are, if you are curious.
Here are three steps leading up to printing the doc for one function only, pr
:
user=> (resolve 'pr)
#'clojure.core/pr
user=> (meta (resolve 'pr))
{:added "1.0", :ns #object[clojure.lang.Namespace 0x66b7550d "clojure.core"], :name pr, :file "clojure/core.clj", :column 1, :dynamic true, :line 3677, :arglists ([] [x] [x & more]), :doc "Prints the object(s) to the output stream that is the current value\n of *out*. Prints the object(s), separated by spaces if there is\n more than one. By default, pr and prn print in a way that objects\n can be read by the reader"}
user=> (#'clojure.repl/print-doc (meta (resolve 'pr)))
-------------------------
clojure.core/pr
([] [x] [x & more])
Prints the object(s) to the output stream that is the current value
of *out*. Prints the object(s), separated by spaces if there is
more than one. By default, pr and prn print in a way that objects
can be read by the reader
nil
The #'
prefix before clojure.repl/print-doc
is there because it lets you use a function in another namespace (`clojure.repl` in this case) even if it is marked private, which print-doc
is.
Learned something today! Isn't that also the syntax for creating a var? In that case, vars bypass the private check?
#'foo
is the same as (var foo)
. It does not create a var -- it tries to resolve to an existing var.
There is probably a more precise way to describe its behavior than "bypassing the private check", but not sure if I know what that more precise way is. Good enough description for now, probably.
I'm I using a wrong syntax to define a binary multi-method?
(defmulti typep
"a doc string"
(fn [a-value type-designator]
(if (seq? type-designator)
(first type-designator)
type-designator)))
(defmethod typep :sigma [_ _]
true)
(defmethod typep :empty-set [_ _]
false)
(defmethod typep :default [a-value a-type]
(if (and (symbol? a-type)
(resolve a-type)
(class? (resolve a-type)))
(isa? (type a-value) (resolve a-type))
(throw (ex-info (format "invalid type designator %s" a-type)
{:type :invalid-type-designator
:a-type a-type
:a-value a-value
}))))
when I try to call it I get an error:
clojure-rte.core> (typep 1 :sigma)
Execution error (ArityException) at clojure-rte.core/eval38559 (form-init8934354515316755715.clj:2894).
Wrong number of args (2) passed to: clojure-rte.type/eval38515/fn--38516
clojure-rte.core>
@jimka.issy you're coming from a lispier lisp I take it 👀
indeed. what's the problem?
clojure is cool. just have to get use to a few things.
no worries, I'm just mentioning it while I see it before I look at the overall problem
did you have another definition of this before that you've now refined (with this being the refinement?)
yes, I used cider-undef
do I need to restart the VM?
even after I restart, I get the same error.
at least it looks the same.
and if I recall, multimethods have issues being redefined during a session (in fact, I recall just having this same issue the other day), although I don't recall why nor if there's a simpler way to fix it without restarting your session
yes, in the repl it works.
what's a session?
maybe its the name typep?
when I name it foo-typep it works.
If I require the namespace using :as, I still get the same error. dammit.
clojure-rte.core> (require '(clojure-rte [type :as ty]))
nil
clojure-rte.core> (ty/typep 1 :sigma)
Execution error (ArityException) at clojure-rte.core/eval38606 (form-init8934354515316755715.clj:3208).
Wrong number of args (2) passed to: clojure-rte.type/eval38515/fn--38516
clojure-rte.core>
Even when I redefine the defmulti to be accept any argument list, the same error happens.
(defmulti typep
"a doc string
(fn [& others]
(let [a-value nil
type-designator nil]
(println (list :typep others a-value type-designator))
(if (seq? type-designator)
(first type-designator)
type-designator))))
ah oh no I had more to write but I'm about to lose internet, if I disappear, that's it
the error and stacktrace are pretty unhelpful.
Show: Project-Only All
Hide: Clojure Java REPL Tooling Duplicates (10 frames hidden)
1. Unhandled clojure.lang.ArityException
Wrong number of args (2) passed to:
clojure-rte.type/eval38515/fn--38516
AFn.java: 429 clojure.lang.AFn/throwArity
AFn.java: 36 clojure.lang.AFn/invoke
MultiFn.java: 233 clojure.lang.MultiFn/invoke
REPL: 3220 clojure-rte.core/eval38620
REPL: 3220 clojure-rte.core/eval38620
Compiler.java: 7176 clojure.lang.Compiler/eval
Compiler.java: 7131 clojure.lang.Compiler/eval
core.clj: 3214 clojure.core/eval
core.clj: 3210 clojure.core/eval
main.clj: 414 clojure.main/repl/read-eval-print/fn
main.clj: 414 clojure.main/repl/read-eval-print
main.clj: 435 clojure.main/repl/fn
main.clj: 435 clojure.main/repl
main.clj: 345 clojure.main/repl
RestFn.java: 137 clojure.lang.RestFn/applyTo
core.clj: 665 clojure.core/apply
core.clj: 660 clojure.core/apply
regrow.clj: 20 refactor-nrepl.ns.slam.hound.regrow/wrap-clojure-repl/fn
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 79 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 55 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 142 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 171 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 170 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 832 java.lang.Thread/run
it would be great if the error message said something like, wrong number of args (2) passed to .... expecting (3), you passed: (the arg list....)
OK, if I can't use multi-methods, how can I write a function which well set an entry destructively into a globally available hash table?
sort of (my-def-method ....)
I'm pretty comfortable with the macrology, just don't know how to create a global mutable resource.
using core.matrix
how can I add/increment a specific row in my matrix?
let's assume 3X3 zero matrix and would like to increment dynamically a row.
(add M [1 1 1])
will do broadcasting,
I can build 3X3 row+2x-empty-rows (`reshape`) and do matrices addition but is there any alternative?
If I have two functions fa
and fb
defined respectively in two name spaces. is there a way for me to make them mutually recursive? Or am I required to refactor my code to put them in the same namespace ?
Don't think there's anything wrong with the code you pasted; you sure you're not working with a stale repl?
(defmulti typep
"a doc string"
(fn [a-value type-designator]
(if (seq? type-designator)
(first type-designator)
type-designator)))
(defmethod typep :sigma [_ _]
true)
(defmethod typep :empty-set [_ _]
false)
user=> (typep 1 :sigma)
true
user=> (typep 1 :empty-set)
false
I've restarted the repl multiple times.
what does cider-restart do? does it restart clojure, or just restart a buffer using the same VM ?\
And a version with namespaces:
(ns user.protocol)
(defmulti typep
"a doc string"
(fn [a-value type-designator]
(if (seq? type-designator)
(first type-designator)
type-designator)))
(ns user.sigma (:require [user.protocol :as p]))
(defmethod p/typep :sigma [_ _] true)
(ns user.empty (:require [user.protocol :as p]))
(defmethod p/typep :empty-set [_ _] false)
(ns user (:require [user.protocol :as p]
[user.sigma]
[user.empty]))
user=> (p/typep 1 :sigma)
true
user=> (p/typep 1 :empty-set)
false
OK, thanks for the confirmation that I'm on the right track.
I'm really puzzled about what's wrong.
great to know.
works like a charm. 🙂
the corresponding slime command is arguably more understandable slime-restart-inferior-lisp
Thanks for the help, guys.
not sure if slime lets you run multiple different CL's scoped to the same and different projects
well i found it unclear. restarting cider i though would restart the underlying lisp
OK, I was mistaken, and I know now.
I'm not sure what the corresponding concept of project is for slime. but yes you can have multiple repls in the same slime session which are all connected to the same inferior lisp.
I doubt slime supports running multiple inferior lisps simultaneously.
when I started using Scala a couple of years ago, the concept of project was really difficult to grasp.
I was attempting to do this with mutimethods, and just define each method in the namespace where its dependencies are visible. but I couldn't get that to work. see message above...
I am looking for a predicate (or a composition of predicates) which could test if a collection is at the same time seqable?
and has a deterministic result order when passed to seq
(excluding the sets collections, for example). Does it exist somewhere in a dark corner of the standard library, or should I just test if it is not a set ?
a kind of consistent-seqable?
?
all collections are seqable and many things that are not collections are seqable
but strings, ArrayList, etc. are seqable and ordered but not sequential?
but if you don't care about seqable, and just care about clojure native collections, sequential?
is what you want
sequential?
is exactly what I need, thanks a lot
anyone know how i can write this more elegantly? :
((if (nil? boop) #(log/infof % %2 %3) #(log/warnf % %2 %3))
"boop [%s] beep [%s]."
boop
beep)))
What is the end goal there? To use either log/infof
vs log/warnf
depending if boop
is nil or not?
Be careful with your use of higher order functions like that, it's an easy beginner anti-pattern which people get trapped in.
@U050MP39D They're not? They take a hof as an argument.
If you need to pass a hof to an existing function off course you have to use one. But if you're writing a function that takes a hof, or using hof in places that don't expect them like here, you should reconsider your approach
a higher order function is a function that takes a function as an argument or returns one
I have no idea what @U0K064KQV could possibly mean by that "They're not?"
the idea is just to keep repeating as little as possible. I didnt want to write an if block that has the log message twice
@UV674TMLM yeah I got you. I agree with the other person though that the repeated code is far far more readable than any of the alternatives. jsn's solution is probably the most readable version without repeated code
Sorry, you guys are correct, I used the wrong terminology. I meant to say anonymous functions
well I'd quibble with that too. I think I'd prefer an anonymous function over partial in almost every case. but that's a personal preference
Don't write such thing, unless you've explored alternatives first and deemed them to be worse
Honestly, I would just write
(let [fmt "boop [%s] beep [%s]."]
(if boop
(log/warnf fmt boop beep)
(log/infof fmt boop beep)))
I learned recently that you can pass a log level to log/logf
like this:
(let [fmt "boop [%s] beep [%s]."]
(log/logf (if boop :warn :info) fmt boop beep))
To me, that looks a lot easier to maintain later on.
It’s possible to be too DRY.
Clojure embraces the bazaar mentality to ecosystem management, which is powerful, but has the drawback of making it hard to get a lay of the land (especially for beginners). What are the best resources to get “best practices” when it comes to tech stacks?
@ryan072 That's a bit too open-ended to answer I think. And you'll get different answers from different folks even if you narrow the focus a bit.
Are you talking about web development? Data science? Front end? Back end? Command-line utilities? Server processes?
honestly, a bit of everything. i guess im asking what “maps” exist they have decent coverage/agreement
You should assume that they all have equal coverage/agreement. Like every lib or framework has equal mindshare. Hopefully that will get you over the OCD of looking to use the "most popular" option by seeing that all options are equally valid in Clojure and are equally being used
Once you get over that hump, which is often there because of your own lack of confidence in being able to judge, so assume that they're all good and worthy of being used, then just choose the one you prefer or like the sound of.
@U0K064KQV I see where you’re coming from, but there are distinct advantages to using “the most” used tools — i.e. better documentation, ongoing development, etc. Was more curious, but this seems to be the biggest issue with a “bazaar” mentality. To be clear, I feel the benefits outweigh the costs long term, but that doesn’t mean the drawback disappears.
It's not like there's a bunch of abandoned options. The bazaar means there's a bunch of options all used in production by different people
there are times when i feel like “someone’s blog said X” is the best I have to go off of
I don't think any such things exist for Clojure. I've seen folks ask about "learning maps" in the past and don't recall them getting a useful answer.
i use https://www.clojure-toolbox.com/ as a reference sometimes, but I still have to evaluate the options enumerated
so, if I want to use the features in my editor (neovim) that are the most important to 99.99% clojure(script) developers (the REPL), I need to use python (wtf), and cider, which is something for emacs? Is that correct?
that's what I disliked in vim as well. Python dependency, even ruby(for the stack that I used). I've switched to emacs ~ 1 year ago(spacemacs in evil mode to be exact) and I wish I made that switch much earlier.
If you're considering a possibility of switching to emacs - FYI: it took me a few days before I felt as productive as I was in vim. It's not that difficult. Evil mode = basically the same exact vim shortcuts but in emacs.
thanks, I like spacemacs very much, but just for one language I can't pick it up, and my other language, javascript, well, very long and frustration story, tl;dr is that I could never configure it for my liking
For Vim I recommend https://github.com/liquidz/vim-iced
Don't know if it also depends on Python, but I think it offers a much better experience then fireplace
only 9% of clojure developers use vim as their primary editor for clojure, so it may be a little rough around the edges
possibly asking in the clojurescript or vim channels might get you better help than me
Fireplace is not the only option. There is https://github.com/Olical/conjure
@hindol.adhya I asked the author of Conjure today and I might've misunderstood but I think he said it was not compatible yet, or not fully, but very soon it's possible that it will be another option
Yes, I saw that, but to my understanding Conjure is written for NeoVim. It might have compatibility issues with Vim but unlikely for NeoVim.
hopefully, you won’t have to write python code. I think that’s just the language neovim plugins are written in.
I have enough trouble with it elsewhere (at work) and in no way I want to deal with all their issues constantly because my dev-env depends on them
@hindol.adhya who said that conjure has compatibility issues with neovim?
there’s no need for name calling. especially since @hindol.adhya is trying to help
> Why would I say something that stupid? this isn’t technically name-calling, but it’s being antagonistic. we’re here to help!
I believe fireplace works with nrepl (rather than cider). nrepl has good integration with emacs, but it’s used by many other ide plugins as well
I am grateful for any help. Misrepresenting my statement and diverting the discussion however is not helpful, I hope I am allowed to state the obvious 🙂
the idea with fireplace, is that you install the plugin, but you won’t have to write/read any python
are you looking for interactive repl or just a repl in general?
@smith.adriane I it says in the docs that > First, set up https://github.com/clojure-emacs/cider-nrepl. (If you skip this step, only a subset of functionality will be available.) I am using an app generated with https://github.com/filipesilva/create-cljs-app It works fine, using devcards even, but would like to have autocompletion in my editor
do you have a link to the docs you’re using?
I couldn’t find where this quote is from: > First, set up https://github.com/clojure-emacs/cider-nrepl. (If you skip this step, only a subset of functionality will be available.)
is that at create-cljs-app?
ah ok.
the two pieces for emacs cider to work well are an emacs plugin (also called cider) and an nrepl server. it turns out the nrepl server can also be used by other ide’s (which fireplace takes advantage of)
much of the documentation is tailored towards the most common workflow(emacs + cider/nrepl)
looks like it
from cider-nrepl link > A collection of https://github.com/nrepl/nrepl middleware originally designed to enhance https://github.com/clojure-emacs/cider.
ok, I started trying vim-iced when I found it, but if it doesn't work out I will try fireplace, thank you very much @smith.adriane for clearing the confusion