beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
gorjusborg 2021-05-18T00:19:21.001800Z

anyone know of any good documentation on how deps.edn works?

gorjusborg 2021-05-18T00:19:44.002300Z

i don't mind reading the code either

gorjusborg 2021-05-18T00:19:59.002500Z

but not sure where it lives

Trevor Martin 2021-05-18T00:22:29.002700Z

https://clojure.org/reference/deps_and_cli

gorjusborg 2021-05-18T00:27:22.002900Z

thanks

đź‘Ť 1
alexmiller 2021-05-18T01:03:09.003900Z

@brandon.n.atkinson there's a link in the above, but https://clojure.org/reference/dep_expansion for more gory details

Franco Gasperino 2021-05-18T04:27:56.005Z

Any options on using a var binding as a require arg, instead of a literal?

phronmophobic 2021-05-18T04:32:24.006Z

like this?

(let [str 'clojure.string]
  (require str))

phronmophobic 2021-05-18T04:33:10.006100Z

do you have an example of what you're trying to do?

Franco Gasperino 2021-05-18T04:35:30.006300Z

(def config {:namespace "clojure.string"})
(let [n (:namespace config)]
  (when (n) (:require [n :as module])))

Franco Gasperino 2021-05-18T04:35:59.006500Z

n is a var, require wants a list/vec of literals

2021-05-18T04:55:09.006700Z

n is "local" not a var

alexmiller 2021-05-18T05:01:09.006900Z

not sure what you're actually trying to do, but requiring-resolve might help

phronmophobic 2021-05-18T05:04:22.007100Z

fwiw, the following works:

(let [config {:namespace "clojure.string"}
      n (:namespace config)]
  (when n (require [(symbol n) :as 'module])))
(module/lower-case "CLOJURE")
but you probably want something like requiring-resolve

Franco Gasperino 2021-05-18T05:44:31.007400Z

thanks for the feedback

Franco Gasperino 2021-05-18T06:07:20.007600Z

im looking for behavior parity between an existing python code base and what can be accomplished here. The python project leverages importlib and dynamic loading in a fashion somewhat similar to java spring ioc, interfaces, and varying implementations.

Franco Gasperino 2021-05-18T06:08:48.007800Z

repl testing looks as if requiring-resolve can provide at least the edn config ->conditional import path here.

Juλian (he/him) 2021-05-18T08:56:40.010200Z

Is there a preferred way to add support for multiple languages? For example, use maps like {:en "Hello, World", :de "Hallo Welt!", etc...} instead of strings and then let the display function choose depending on chosen language?

Juλian (he/him) 2021-05-19T09:36:04.062500Z

Thanks again! I think I'll avoid nesting too deep, then. Maybe even use a separate dictionary for each category, like one for item names, one for item descriptions. Then I can use the keyword for the item as resource id (in this example, :sword).

pithyless 2021-05-19T11:27:54.063700Z

My gut reaction would be to have :item/sword or even :item.weapon/sword wherever you're dealing with the thing and then use the keyword/string logic to map all translations (so you automatically map :item/sword to {:item.sword/name ".." :item.sword/description ".."})

pithyless 2021-05-19T11:29:31.063900Z

Having unambiguous full-qualified keywords as identifiers means you can mix-and-match maps easier and pass things around without nesting for context. It seems like a small difference, but it has some nice long-term benefits that are not easy to articulate until you start growing bigger systems with it.

pithyless 2021-05-19T11:30:16.064100Z

Check out https://www.youtube.com/watch?v=IS3i3DTUnAI if you want to learn more about the perks of fully-qualified keywords

pithyless 2021-05-19T11:36:25.064400Z

{:item/id :magic-sword-of-parens ;; or more unique ala :<http://item.id/magic-sword-of-parens|item.id/magic-sword-of-parens>
 :item/kind :item.kind/weapon
 :item/weapon :item.weapon/sword
 :item/name "this is dynamically generated based on translation, but is generic key for UI"
 :item/description "same here"} 
^ Perhaps too much ceremony for you, but notice that all those keywords can be used in different parts of the codebase without any additional context and data - and you know exactly what they are.

practicalli-john 2021-05-18T09:26:15.013200Z

Any suggestions as to why (<http://clojure.java.io/resource|clojure.java.io/resource> "config.edn") is returning nil even though the config.edn file is on the classpath, as shown by lein classpath command? Its an older Clojure project with Leiningen. I tried using Java 8 and Java 11, a few different versions of Leiningen. I can slurp the file...

practicalli-john 2021-05-18T09:57:06.013700Z

Is there a way to see the classpath from the REPL ??

practicalli-john 2021-05-18T10:00:47.014800Z

I have tried some variations around this example, https://gist.github.com/ekoontz/1502838 but I get nil returned. I though the code wasnt working, but perhaps Leiningen is not correctly setting the classpath for the repl, which would explain the issue

pithyless 2021-05-18T10:01:37.015400Z

@julian608 In case you're not familiar with this domain, you can find a plethora of stuff to read about searching for internationalization and localization (abbreviated as i18n and l10n ). There is a lot of nuance to doing this well at scale. But if you're just looking for something quick to get you started grab an existing i18n library (e.g. https://github.com/ptaoussanis/tempura) and try not to go down the rabbit hole of learning everything about this - the well runs very deep. :)

practicalli-john 2021-05-18T10:02:07.016200Z

Curious that this code returns the leiningen jar as the class path, rather than the really long classpath I get when using lein classpath command

(doseq [url (seq (.getURLs (java.lang.ClassLoader/getSystemClassLoader)))]
       (println (.getFile url)))

jumar 2021-05-18T10:03:41.016300Z

What I use most often is cider-open-classpath-entry There's also a system property for this:

(System/getProperty "java.class.path")

đź‘Ť 1
Juλian (he/him) 2021-05-18T10:25:23.016500Z

That looks nice, thanks!

Juλian (he/him) 2021-05-18T10:28:24.016700Z

I load a few files using io/resource, they all are in the resources folder

practicalli-john 2021-05-18T10:43:14.017400Z

Definitely something in the Leiningen project messing up the classpath when running the repl either on the terminal or via the editor. I think Leiningen has been silently failing to build the classpath. Also it seems Leinigen was not downloading all dependencies.

2021-05-19T14:40:18.072400Z

$ lein deps :tree also helps diagnose transative dep problems, and $ lein help sample has example based docs of most of lein's weird features

practicalli-john 2021-05-19T18:52:54.093200Z

I found an issue with a transitive dependency of a transitive dependency. There were also issues with a user.clj file, which was automatically loaded on startup by Leiningen. The repl runs now, thanks all.

2021-05-19T19:05:15.094400Z

leiningen does not autoload user.clj, but clojure does (if it's seen on classpath) - perhaps the difference was lein putting the file on classpath

2021-05-19T19:05:37.094600Z

a transitive dep of a transitive dep is a transitive dep (by the transitive property :D)

đź‘Ť 1
pavlosmelissinos 2021-05-18T11:06:44.018900Z

(defn my-fn [{:keys [unparam1 unparam2]
              :param/keys [param1 param2 param3]
              param-type :param/type
              :as params}]
...)
I have a function that looks like the above. Is there a more intuitive way (the change of the order throws me off quite a bit) to rebind ::param/type to param-type? The goal is to avoid having to use the name type to refer to this parameter within the scope of the function. I think it would be nice to be able to say something like {::param/keys [param1 [type :as param-type]]}

practicalli-john 2021-05-18T11:51:21.019300Z

Hmm, this just shows the leiningen jar as the class path. very strange.

practicalli-john 2021-05-18T11:52:14.019500Z

I can use io/resources in a newly created project. There is something strange in this legacy project that is messing with the class path I think.

jumar 2021-05-18T12:33:18.021200Z

It works fine for me. I’ve been using it for a long time from jdk 8 to jdk 16. Note that your code fails completely on modern JDKs

jumar 2021-05-18T12:34:32.022600Z

Just in case: it’s always good to try lein clean if you experience weird issues

2021-05-18T13:10:35.023200Z

try lein with-profile +repl cp to get the classpath a repl would use

2021-05-18T13:10:44.023400Z

you can swap in other profiles of course

2021-05-18T13:11:08.023600Z

also for io/resource to work, the document shouldn't be on classpath, its parent folder or zip file / other container should be

2021-05-18T13:12:29.024100Z

nb. "." shouldn't be on classpath, you should have specific subdirectories of the project like src and resources that are on classpath

2021-05-18T13:14:14.024300Z

if it was "failing to build a class path" java wouldn't even be able to run anything. what is happening is you are asking for a different classpath than you think you are.

2021-05-18T13:15:53.024500Z

> it seems Leinigen was not downloading all dependencies. that makes me think that something replaced the classpath / dep vector where it should have been adding to it (look for the ^:replace metadata in a profile for example)

practicalli-john 2021-05-18T13:21:32.024700Z

Yes, the code does work correctly in a new project. It gives the leinigen path in the older project, I think because something is failing... Thanks.

2021-05-18T14:32:30.026200Z

Hey everyone, is there a concept of a spread operator in Clojure? I want to merge a map with a sequence of maps, but I want to 'spread' out that sequence.

alexmiller 2021-05-18T14:33:24.026400Z

apply

practicalli-john 2021-05-18T15:08:45.026500Z

The project does something intricate with project.clj and profiles.clj (which is also in the root of the project). I commented out all the bits I didnt understand and at least I have a proper class path now. I also decided to add a deps.edn file and use Clojure CLI tools. This showed some issues with transitive dependencies which I've now resolved.

Erik B Good 2021-05-18T16:06:24.029700Z

Hi, I was wondering if there was any way of making some simple dfs traversal work with recur? I understood that recur uses tail optimisation which is not otherwise possible given the JVM. Now , if I simply replace my recursive call to dfs, I get an error 'Can only recur from tail position'. Is there a clojurian way of making this sort of code work with tail optimisation? Thank you very much for your help. (*fn* dfs [tree traversed] (*let* [node (first tree) c1 (second tree) c2 (nth tree 2)] (*if* (nil? tree) (conj traversed tree) (concat [node] (dfs c1 traversed) (dfs c2 traversed)))))

2021-05-18T16:24:21.030200Z

in order to tail recur over a tree you need to lift the rest of the tree traversal into a data structure, which leads to harder to read code. except when you have extreme efficiency needs, the right thing to do is just consume stack proportional to the tree size

2021-05-18T16:24:42.030300Z

by simple non-optimized self call

2021-05-18T16:27:16.030400Z

also your lazy structure via putting the self call inside concat already prevents stack usage explosion I think?

2021-05-18T16:34:05.030500Z

I think typical default max JVM stack depth is on the order of a few thousand calls (it can be configured larger when you start the JVM via command line options). If you expect the DFS to traverse more nodes than that at maximum depth, then you should consider whether you might want to use a method that manages the DFS control flow via a data structure, vs. consuming call stack.

Karo 2021-05-18T18:10:56.033500Z

hi team, I am facing this issue during deployment after changing java10 to 11 version. I also added JAXB library but the issue is still there. any suggestion? can this be related to the leiningen version as well?

2021-05-18T18:13:52.034Z

you find yourself in a twisty maze of passages, all alike

đź‘Ś 1
2021-05-18T18:15:24.034600Z

you are building an uberjar, and if you find the file named module-info.java in the uberjar and remove it, then maybe that will fix things

2021-05-18T18:16:59.035Z

you can maybe use this https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L422 to do it automatically

2021-05-18T18:20:52.036700Z

not 100%, but my guess is some dependency you are pulling in includes some java module stuff, and that is all be blindly shoveled into the uberjar by lein, so then java now thinks your uberjar is a java module thing, which makes things weird

Charlie Mead 2021-05-18T20:06:03.037100Z

For anyone who’s perused https://www.manning.com/books/the-joy-of-clojure-second-edition?gclid=CjwKCAjwy42FBhB2EiwAJY0yQlgELvVtu7ErEKP-G0m9lqeWm4wS0BInny8yz1tHUxVM4gALeSBVohoCXVIQAvD_BwE, I was re-reading a section this morning and hit a point of confusion. In 8.1.1, there’s a quick review of syntax-quote, unquote, and splicing, with the example function contextual-eval:

(defn contextual-eval [ctx expr]
  (eval
   `(let [~@(mapcat (fn [[k v]] [k `'~v]) ctx)]
      ~expr)))
The author then writes: > The bindings created use the interesting '~s` pattern to garner the value of the built bindings at runtime. I don’t understand why '~s` is necessary/what problem it solves here. It seems redundant to me. When I attempted to write my own contextual-eval, I ended up with:
(defn contextual-eval [ctx exp]
    (eval `(let [~@(mapcat (fn [[k v]] [k v]) ctx)]
       ~exp)))
And it looks like the examples from the book evaluate to the same thing using my version.
(contextual-eval '{a 1 b 2} '(+ a b)) ; 3
(contextual-eval '{a 1 b 2} '(let [b 1000] (+ a b))) ; 1001

phronmophobic 2021-05-18T20:14:54.037500Z

I'm not sure I would write it the same as their example, but there's a difference in behavior. Eg:

(defn contextual-eval [ctx expr]
  (eval
   `(let [~@(mapcat (fn [[k v]] [k `'~v]) ctx)]
      ~expr)))


(defn contextual-eval-mead [ctx exp]
    (eval `(let [~@(mapcat (fn [[k v]] [k v]) ctx)]
             ~exp)))

(contextual-eval '{a (+ 0 1) b 2} '(+ a b)) ;; exception
(contextual-eval-mead '{a (+ 0 1) b 2} '(+ a b)) ;; 3
Notice that they quote the value in their implementation

Erik B Good 2021-05-18T20:18:01.037700Z

Thank you folks

phronmophobic 2021-05-18T20:18:56.037900Z

I haven't read the book and maybe it makes sense for their example, but calling eval in a macro seems super weird to me

Charlie Mead 2021-05-18T20:19:42.038100Z

Oh it’s not a macro yet — just a regular fn being used to introduce the concept of macros

phronmophobic 2021-05-18T20:20:17.038300Z

ohhh, right. duh. nvmd :homerdisappear:

Charlie Mead 2021-05-18T20:21:05.038600Z

Thanks for your response earlier, walking through it now

phronmophobic 2021-05-18T20:26:06.038800Z

it's a little easier to see what's going on if you just show the code being passed to eval:

(defn contextual-eval-form [ctx expr]
  (let [form `(let [~@(mapcat (fn [[k v]] [k `'~v]) ctx)]
                ~expr)]
    form))

(defn contextual-eval-mead-form [ctx exp]
  (let [form `(let [~@(mapcat (fn [[k v]] [k v]) ctx)]
                ~exp)]
    form))

(contextual-eval-form '{a (+ 0 1) b 2} '(+ a b))
;; (clojure.core/let [a '(+ 0 1) b '2] (+ a b))

(contextual-eval-mead-form '{a (+ 0 1) b 2} '(+ a b))
;; (clojure.core/let [a (+ 0 1) b 2] (+ a b))
Their's has a ' before (+ 0 1)

đź‘Ť 1
Charlie Mead 2021-05-18T20:26:28.039Z

It makes sense why the book version breaks, but I’m still confused as to why it might be the preferred/idiomatic version vs. the simpler one. Trying to think of an example where contextual-eval-mead would be worse…

phronmophobic 2021-05-18T20:31:27.039300Z

well, for the purposes of introducing macros, their version is closer to how a macro works

phronmophobic 2021-05-18T20:32:14.039500Z

a macro gets unevaluated forms which is what their version is doing

đź‘Ť 1
Charlie Mead 2021-05-18T20:32:27.039700Z

ah ok. maybe that’s the use of having it in there then.

Charlie Mead 2021-05-18T20:32:38.040Z

thanks

2021-05-18T20:52:27.040200Z

I recently came across a use of this in the malli codebase: https://github.com/metosin/malli/blob/master/src/malli/core.cljc#L1969

phronmophobic 2021-05-18T20:55:32.040500Z

I usually would write that as:

(list 'quote (symbol (str name)))
it's a little more verbose, but it's easier for my brain to follow

đź‘Ť 1
2021-05-18T21:04:37.040700Z

interesting, it's good to have the comparison - thanks!

phronmophobic 2021-05-18T21:06:30.040900Z

the '~` idiom is a neat trick though. Might be worth getting used to.

lunik1 2021-05-18T22:05:16.047200Z

I'm working my way through The Reasoned Schemer using core.logic and I'm having some trouble with the nevero goal defined in Chapter 6 frame 14:

(defrel (nevero)
  (nevero))
This should be a goal that never succeeds and never fails. My naĂŻve translation to Clojure is
(defn nevero [] (nevero))
According to the book, Chap. 6 frame 17
(run 1 q
  #u
  (nevero))
should produce (), as #u fails before nevero is encountered, but
(run 1 [q] u# (nevero))
does not terminate for me (well, it does when it blows the stack). Does core.logic behave differently here or have I goofed something up?

lunik1 2021-05-19T23:41:39.120Z

..but thinking about it I'm still not entirely sure why

Ethan Plante 2021-05-18T22:06:31.048Z

Hello! I'm 9 days into learning Clojure. How do you all approach solving problems?

phronmophobic 2021-05-18T22:13:20.048100Z

For an in-depth look at problem solving techniques, G. Polya's "How to Solve It" is great, http://www.math.utah.edu/~pa/math/polya.html

phronmophobic 2021-05-18T22:14:36.048300Z

The overview is a good starting point: 1. Understanding the problem 2. Devising a plan 3. Carrying out the plan 4. Looking back (eg. testing)

Juλian (he/him) 2021-05-18T22:29:17.048800Z

there has to be a better and safer way than (keyword (str "example." (name :foo)) "bar") (with :foo coming from a parameter). to give more context, I want to put all item names for my game into that dictionary, nested under :item - so for example :item {:sword {:name "Sword", :description "A Sword with a sharp blade."}} and when outputting the name of the item, I would have :sword and want to call tr with :item.sword/name - is this a valid approach or should I rethink it?

orpheus 2021-05-18T23:11:15.052800Z

I have two files/namespaces that alias two different namespaces with the same symbol and I’m getting an alias conflict error. Why can’t I use the same-symbol (`:as some-symbol` ) when referring to two different namespaces in two different files?

// one.clj
(ns com.app.one
  (:require [com.app.models.one :as model]))

// two.clj
(ns com.app.two
  (:require [com.app.models.two :as model]))

phronmophobic 2021-05-18T23:13:15.053100Z

looks ok to me. Maybe it's some other issue. What's the error you're getting? What's the symbol alias you're trying to use?

orpheus 2021-05-18T23:14:39.053300Z

1. Caused by java.lang.IllegalStateException
   Alias model already exists in namespace
   neuromancer.core.pay.invoice, aliasing
   neuromancer.models.pay.account
I’m using :as model in both *.pay.invoice and *.pay.account

orpheus 2021-05-18T23:16:24.053500Z

If I change the alias for one of them, it compiles w/o error

phronmophobic 2021-05-18T23:17:43.053700Z

is there another require in the same namespace using model?

phronmophobic 2021-05-18T23:18:02.053900Z

what do you mean by compile?

orpheus 2021-05-18T23:18:39.054100Z

using cider’s hot key C-c c-k to compile the current namespace

orpheus 2021-05-18T23:19:16.054300Z

and no I just have 3 requires in this namespace, only one aliasing :as model

phronmophobic 2021-05-18T23:19:20.054500Z

ah, I'm guessing there's some persistent state which won't let you change it

phronmophobic 2021-05-18T23:19:44.054700Z

you can either restart your repl or run

(ns-unalias *ns* 'model)

phronmophobic 2021-05-18T23:19:56.054900Z

for each namespace before trying again

orpheus 2021-05-18T23:20:01.055100Z

Cool let me give that a shot

phronmophobic 2021-05-18T23:24:01.055300Z

there's probably a better way to reload each namespace without restarting the repl, but my repl workflow is fairly basic

orpheus 2021-05-18T23:28:49.055500Z

Yeah there’s something weird going on with my repl. I restarted it, and it stopped giving me that error, but now It’s giving some other error that also looks like a caching problem

phronmophobic 2021-05-18T23:31:41.055700Z

progress!

orpheus 2021-05-18T23:31:57.055900Z

Ah nah figured it out, now everything’s compiling! just needed to restart the repl, thank you 🙂

🎉 1