clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
2021-01-04T05:15:30.297700Z

I'm not sure you even need to do this, can't you just bind *ns* with binding?

2021-01-04T05:19:00.298Z

pmap will max out concurrency at max cpu + 2 or the chunk size if given a lazy-seq

2021-01-04T05:30:01.298300Z

So you can kind of control the concurrency level by controlling the chunk size like so:

(defn re-chunk [n xs]
  (lazy-seq
    (when-let [s (seq (take n xs))]
      (let [cb (chunk-buffer n)]
        (doseq [x s] (chunk-append cb x))
          (chunk-cons (chunk cb) (re-chunk n (drop n xs)))))))

(time (dorun (pmap (fn[e] (Thread/sleep 100) (inc e)) (re-chunk 100 (range 1000)))))

"Elapsed time: 1038.57 msecs"

2021-01-04T05:30:50.298500Z

So you can just call re-chunk on the collection before passing it to pmap, and give it the chunk size you want, that will also be the concurrency level.

2021-01-04T05:33:48.298700Z

That said, to the original question, I would use an Executor with some fixed thread count which is scaled either to the API I call, or the service I am using.

clyfe 2021-01-04T07:37:44.299100Z

in-ns also creates the ns if needded

Karol Wójcik 2021-01-04T08:06:47.299900Z

Did anyone encounter the following error on java11? Caused by: java.lang.Exception: Cyclic load dependency: [ /clojure/spec/alpha ]->/clojure/walk->[ /clojure/spec/alpha ]->/clojure/main->/clojure/core/server

p-himik 2021-01-04T08:11:38.300100Z

IIRC I've seen people report this when they add Clojure sources to their classpath along with the jar. But maybe that's not it in this case.

Karol Wójcik 2021-01-04T08:13:35.300300Z

Encountered it here: https://github.com/FieryCod/holy-lambda/issues/26

Karol Wójcik 2021-01-04T08:23:06.300600Z

The error occurs when using clojure >= 1.10.0 only on java11

2021-01-04T09:06:05.300900Z

Hard to say exactly, but my guess is it is some kind of aot related issue. This is kind of hard to wade through (for example the source for the lein plugin doesn't seem to be the repo?) but we can discount the existence of an actual cyclic dependency in clojure. My guess is an aot issue, just because it often is, but I can't recall an aot issue presenting as a cyclic dependency. The repo looks like it is library code, but is also marked to aot compile everything when building an uberjar. Both of which are big red flags with library code. Library code should not be uberjared or aot compiled.

Karol Wójcik 2021-01-04T10:01:17.302500Z

Thanks @hiredman! Will check whether removal of aot helps

Karol Wójcik 2021-01-04T11:12:50.302700Z

@hiredman Removed aot compile for library. Allowed aot compilation for hello-lambda code. Still the same errors is there. Maybe Alex would know the answer? EDIT: When trying clojure:1.10.0 (removing require of clojure.walk) and compiling on java8, but still running on java11 the error is different:

Caused by: Syntax error macroexpanding clojure.core/defn at (clojure/spec/alpha.clj:78:1).
	at clojure.lang.Compiler.checkSpecs(Compiler.java:6972)
	at clojure.lang.Compiler.macroexpand1(Compiler.java:6988)
	at clojure.lang.Compiler.macroexpand(Compiler.java:7075)
	at clojure.lang.Compiler.eval(Compiler.java:7161)
	at clojure.lang.Compiler.load(Compiler.java:7636)
	at clojure.lang.RT.loadResourceScript(RT.java:381)
	at clojure.lang.RT.loadResourceScript(RT.java:372)
	at clojure.lang.RT.load(RT.java:459)
	at clojure.lang.RT.load(RT.java:424)
	at clojure.core$load$fn__6839.invoke(core.clj:6126)
	at clojure.core$load.invokeStatic(core.clj:6125)
	at clojure.core$load.doInvoke(core.clj:6109)
	at clojure.lang.RestFn.invoke(RestFn.java:408)
	at clojure.core$load_one.invokeStatic(core.clj:5908)
	at clojure.core$load_one.invoke(core.clj:5903)
	at clojure.core$load_lib$fn__6780.invoke(core.clj:5948)
	at clojure.core$load_lib.invokeStatic(core.clj:5947)
	at clojure.core$load_lib.doInvoke(core.clj:5928)
	at clojure.lang.RestFn.applyTo(RestFn.java:142)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$load_libs.invokeStatic(core.clj:5985)
	at clojure.core$load_libs.doInvoke(core.clj:5969)
	at clojure.lang.RestFn.applyTo(RestFn.java:137)
	at clojure.core$apply.invokeStatic(core.clj:667)
	at clojure.core$require.invokeStatic(core.clj:6007)
	at clojure.main$loading__6721__auto____8974.invoke(main.clj:11)
	at clojure.main__init.load(Unknown Source)
	at clojure.main__init.<clinit>(Unknown Source)
	... 58 more
Caused by: java.lang.Exception: #object[clojure.spec.alpha$and_spec_impl$reify__2387 0x69d45cca "clojure.spec.alpha$and_spec_impl$reify__2387@69d45cca"] is not a fn, expected predicate fn

vemv 2021-01-04T12:07:41.305900Z

Should I try brew cask install -ing both adoptopenjdk/openjdk/adoptopenjdk11 and adoptopenjdk/openjdk/adoptopenjdk8? Will it work? (while being able to switch versions at will) (don't want to try it right now, lest I break my dev env) ...I'm aware that jenv and sdkman exist. Hadn't had the need so far, although I'm willing to use them

katox 2021-01-04T14:07:28.306700Z

I bumped into this with Figwheel. It culprit was cljc dir in the target dir, ie twice. Once in src/ and the second in target/.

seancorfield 2021-01-04T17:27:32.310400Z

I have a bunch of env vars set in my .profile so I can easily specify JAVA_HOME=$OPEN_JDK<n> at the start of any command to run whatever version I need for that command.

👍 1
seancorfield 2021-01-04T17:27:45.310800Z

(I have 8, 11, 14, 15 installed right now)

seancorfield 2021-01-04T17:29:01.311600Z

lein clean often helps @karol.wojcik

Tim Robinson 2021-01-04T17:33:42.314Z

Hi everyone. I've noticed that if you call realised? on a delay that is has already started evaluating, the call blocks until realised? is true rather than immediately returning false e.g. in the REPL

(def my-delay (delay (Thread/sleep 5000)))
(future (@my-delay))
(realized? my-delay)
The last line will wait 5 seconds before returning true. Is this a bug? is there any way of getting the behaviour I was expecting?

Karol Wójcik 2021-01-04T17:34:04.314100Z

Hi @seancorfield. Thank you for an advice! Unfortunately it does not help either. Moved with discussion to this thread https://clojurians.slack.com/archives/C1B1BB2Q3/p1609759205028100

clyfe 2021-01-04T17:40:37.315400Z

> When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object.

seancorfield 2021-01-04T17:42:27.315600Z

I think it's at least partly to avoid Shrodinger stuff: a delay is either pending or ready -- you can't observe it "getting ready"

Tim Robinson 2021-01-04T17:50:12.316Z

hmm ok. In my current design I've got a time-consuming task which several threads might be waiting for, so I put it in a delay, but I guess that's not what delay is meant for, since clojure code is supposed to avoid locking. I guess I need to re-think it.

clyfe 2021-01-04T17:51:32.316200Z

You probably want to check .isDone on the future

seancorfield 2021-01-04T17:59:17.316400Z

Well, you can't use a value until it is available. What do those other threads do if the value is not available (yet)? If they simply spin and wait for it, why not have them just use a deref and block? If they have other work to do, use a future instead of a delay perhaps? realized? doesn't block on a future (it calls .isDone under the hood).

Tim Robinson 2021-01-04T18:13:58.316900Z

I'm trying to create a kind of cache of memoized results, where if a thread wants something that is already being processed, it just waits for the existing computation to finish. The cache is an atom so I can't swap! a future into it, because creating a future has a side-effect, so I create it as a delay then deref it once the swap is done. Now I'm trying to clear down stale results from the cache so obviously I want to ignore any that are still being computed.

belun 2021-01-04T18:14:22.317500Z

i have a scripts/build.clj file that define a function deploy-build. how do i run that (from a terminal)?

Tim Robinson 2021-01-04T18:18:02.317600Z

maybe I can just put a promise in the cache and have a free-running future that signals the promise when it's done

👍 1
clyfe 2021-01-04T18:20:31.317800Z

Depends what's in it. See if this helps: https://clojure.org/guides/deps_and_cli https://clojure.org/reference/deps_and_cli

belun 2021-01-04T18:22:49.318300Z

this the file

belun 2021-01-04T18:25:57.318500Z

hm actually i need to run the whole .clj file

belun 2021-01-04T18:26:28.318700Z

deploy-build is just something used during a build/watch

clyfe 2021-01-04T18:28:35.319200Z

clj -M /path/to/myscript.clj

belun 2021-01-04T18:31:12.319400Z

ok so i needed the -M option

belun 2021-01-04T18:31:15.319600Z

now i get

belun 2021-01-04T18:31:34.319800Z

clj -M ./scripts/build.clj
Syntax error (FileNotFoundException) compiling at (E:\workspace-clj\screeps-cljs\.\scripts\build.clj:1:1).
Could not locate cljs/build/api__init.class, cljs/build/api.clj or cljs/build/api.cljc on classpath.

belun 2021-01-04T18:32:04.320Z

i need to set something in the classpath? or something?

belun 2021-01-04T18:32:50.320200Z

seems that it does not even pass the first require

borkdude 2021-01-04T18:33:20.320500Z

@belun that file is part of a leiningen project with this project.clj: https://github.com/anisoptera/screeps-cljs/blob/master/project.clj

borkdude 2021-01-04T18:33:31.320800Z

the only way you can run that is through leiningen

belun 2021-01-04T18:34:10.321Z

i have lein but still dont know how to run and trigger the whole thing

borkdude 2021-01-04T18:34:50.321200Z

The README of that project suggests you run this script: https://github.com/anisoptera/screeps-cljs/blob/master/scripts/watch

belun 2021-01-04T18:35:50.321500Z

damn i saw that in the readme but was not seeing the shell script

belun 2021-01-04T18:35:53.321700Z

on windows

borkdude 2021-01-04T18:36:17.321900Z

I guess on windows you would leave out rlwrap but the rest should more or less work, give or take a few slashes

belun 2021-01-04T18:38:15.322400Z

clojure.lang.ExceptionInfo: failed compiling file:src\screeps\memory.cljs {:file #object[java.io.File 0x2bc0b8c8 "src\\screeps\\memory.cljs"]}

Caused by: clojure.lang.ExceptionInfo: No such namespace: cognitect.transit, could not locate cognitect/transit.cljs, cognitect/transit.cljc, or Closure namespace "cognitect.transit" {:tag :cljs/analysis-err
or}

belun 2021-01-04T18:38:25.322600Z

now i am guessing i am missing some dependency

belun 2021-01-04T18:38:36.322800Z

the project seems v old

borkdude 2021-01-04T18:39:04.323100Z

yeah, that's weird. he mentions transit in the README, but it doesn't seem part of the project.clj

borkdude 2021-01-04T18:39:26.323300Z

but you could add it

borkdude 2021-01-04T18:39:55.323500Z

https://github.com/cognitect/transit-cljs

belun 2021-01-04T18:41:04.323900Z

yea trying to add and run [com.cognitect/transit-clj "1.0.324"]

belun 2021-01-04T18:43:08.324100Z

except i need the cljs one :

[com.cognitect/transit-cljs "0.8.264"]

borkdude 2021-01-04T18:43:12.324300Z

yes

belun 2021-01-04T18:43:58.324600Z

um

belun 2021-01-04T18:44:09.324800Z

some warning on that transit script

belun 2021-01-04T18:44:10.325Z

but

belun 2021-01-04T18:44:17.325200Z

export SCREEPS_USERNAME and SCREEPS_PASSWORD (optionally SCREEPS_BRANCH) to autodeploy code.

belun 2021-01-04T18:44:30.325400Z

this is the error message from the build.clj

belun 2021-01-04T18:44:35.325600Z

is great so far

hackeryarn 2021-01-04T20:35:09.327200Z

I have a macro question that has me stumped. What's a good way to check if a passed in argument is a function? I thought fn? would work but it doesn't work in a macro as I expected since the macro receives a symbol or a cons with the fn definition. Simplified example of what I'm trying to accomplish:

(defn make-comparison-expr [field compare]
  (if (fn? compare)
    `(~compare ~field)
    `(= ~compare ~field)))
I probably need to resolve compare, but I am not sure what's the best way to do so in this case. An ugly way that works for this scenario:
(if (or (and (symbol? compare) (fn? @#'compare))
            (and (seq? compare) (= 'fn* (first compare))))
      `(~compare ~field)
      `(= ~compare ~field))))

2021-01-04T20:46:07.328100Z

This kind of thing is usually a good indicator that you shouldn't be using a macro

2021-01-04T20:52:23.333Z

When binding names to values (via let, def, function invocation, etc) the name is known statically (at compile time) while the value is dynamic (known at runtime). Macros are functions that run at compile time, so there is a fundamental mismatch if you are writing a macro that tries to examine the values names are bound to

2021-01-04T20:53:36.334800Z

There is kind of an exception to this for defs, because previous defs run, so their value is part of the compile time environment of the next top level form

2021-01-04T20:55:19.336700Z

But there are other ways to bind names, and your macro won't work correctly for them

hackeryarn 2021-01-04T21:00:31.340300Z

Thanks for the details explanation. That's a good point about not knowing what's being referenced at macro eval time. I tried lifting this check to runtime, and it works but generates some pretty odd code. e.g.

(if (fn? 1)
  (1 1)
  (= 1 1))
Maybe I shouldn't worry about avoiding code like that since (1 1) will never run, but I felt like it's something I should avoid. Also I will need to mess with eastwood to get rid of the linting error.

2021-01-04T21:03:33.341400Z

You may also want to use ifn? instead too

2021-01-04T21:04:42.342800Z

fn? is only true for a surprisingly small subset of things that can be invoked as a function

2021-01-04T21:05:47.343800Z

For example if I recall, fn? Is false for multimethods

hackeryarn 2021-01-04T21:09:45.346600Z

Ah did not know about multi methods. I originally chose fn? to avoid keywords returning true in this case. But maybe it makes more sense to go the other way around and use ifn? but give keywords special treatment.

2021-01-04T21:22:14.347Z

or just assume you will always be passed a callable thing

2021-01-04T21:22:42.347600Z

and pass #(= % whatever) if you want the comparison case

2021-01-04T21:22:55.347900Z

(or (partial = whatever) )

dpsutton 2021-01-04T21:24:46.348800Z

macro sugar can often not be worth it. they feel pretty silly to me too if they just serve to prevent you from having to write (fn [] ) around a body

✔️ 1
dpsutton 2021-01-04T21:25:36.349200Z

not saying that's your case here but that's a common occurrence in the wild

hackeryarn 2021-01-04T21:28:06.350600Z

That would definitely simplify things a lot here. Probably too much of my common lisp thinking bleeding through when trying to write this 😄

hackeryarn 2021-01-04T23:31:34.351400Z

Thanks for all the discussion and suggestions. I settled on having two versions of my macro. A plain version that handles the = case (which is 80% of the time), and a version with -by appended that only takes callable things. It really simplified the design and overall code.

dpsutton 2021-01-04T23:34:29.352100Z

are you sure you needed a macro? i didn't follow along too much but it seemed it was just performing a check or returning a function to do so?

hackeryarn 2021-01-04T23:42:56.357400Z

I'm making a little query dsl. The main purpose being to keep the intent of the query simple and easy to follow. Mainly using the macro to make things easier for the readers of the code.

seancorfield 2021-01-04T23:44:53.359600Z

@hackeryarn You may find https://github.com/clojure-expectations/clojure-test interesting code to read over: it provides a testing DSL where you can say (expect 1 1) and it tests they are equal or (expect odd? 1) and it tests the value using the predicate.

seancorfield 2021-01-04T23:45:28.360300Z

(it macroexpands to regular clojure.test assertions)

hackeryarn 2021-01-04T23:48:31.361500Z

Thanks @seancorfield that's exactly the type of syntax I was trying to accomplish!