Fork me on GitHub
#beginners
<
2020-10-21
>
Jim Newton11:10:23

what is the name of the clojure function which concatenates the elements of a sequence in some fashion but interposes an optional delimiter such as converting [1 3 2 4] to "1,3,2,4" ? Basically how should I print the elements with comma between adjacent elements, but no comma at beginning nor end?

walterl11:10:22

Oh, nm 😛

Jim Newton11:10:58

interpose is interesting as a generalisation of join

souenzzo12:10:30

Why not just pr-str? It will generate [1, 2, 3, 4]

Jim Newton12:10:59

with spaces? I don't need the spaces.

kennytilton18:10:05

@U010VP3UY9X (cl-format nil "{a^,}" nums) 🙂

Jim Newton09:10:46

i've never made myself learn the looping options of format but I love it when i see it in action

🍺 3
kennytilton13:10:18

I once did a mildly hairy cl-format for production code but before making the PR thought I should rewrite for the benefit of the Klojure Kids, one of whom had already said he did not know it existed (but seemed enthusiastic). The rewrite was monstrous, so I left it in: better they should learn cl-format and be empowered forever.

Jim Newton08:10:24

I love/hate CL:FORMAT the same goes for CL:LOOP

Jim Newton08:10:42

one nice thing that motivates me to use clojure's cl-format is the fact that ~a expands lazy sequences. I hate getting the occasional error message containing the non-content of the lazy sequence which my code wasn't expecting. 😞 using cl-format for all error messages eliminates this risk.

kennytilton11:12:06

I eschewed LOOP for years. It is brilliant. Quirky, but hey, it's a DSL for iteration, worth the time. Give it a month?

Jim Newton11:10:06

I found it, it's called join

Nassin16:10:50

what's wrong here? ((symbol (first '("java.util.Date."))))

noisesmith16:10:19

what do you expect to happen when you call a symbol with no args?

noisesmith16:10:38

it's eval that turns the symbol into the constructor, but you aren't using eval here

dpsutton16:10:12

(symbol (first '("java.util.Date."))) -> the symbol java.util.Date. so a minimal example of what you are doing here is ('a) which results in the error "Wrong number of args (0) passed to: clojure.lang.Symbol"

Nassin17:10:18

why does ('a 10) work?

noisesmith17:10:05

because symbols can be called, they look themselves up in their argument

noisesmith17:10:39

user=> ('a '{a 10 b 20})
10

noisesmith17:10:09

even better

user=> ('java.util.Date. '{java.util.Date. 42})
42

Nassin17:10:27

oh right, like keywords

andy.fingerhut17:10:30

If your question is: Why doesn't that throw an exception, because 10 is not a collection, then the answer is that those expressions, as well as the get function, have always done so (i.e. have always returned nil in that situation rather than throwing an exception), and hopefully an FAQ answer written in the near future will have the answer to why it was designed that way. It is surprising to many people when they first encounter it.

Nassin17:10:06

@andy.fingerhut to enable nil punning?

andy.fingerhut17:10:44

That might be it. That would explain why ('a nil) doesn't throw an exception, but not necessarily why ('a 10) doesn't throw an exception.

noisesmith17:10:39

the typical answer in things like this is that the extra type check makes for less hotspot improvement

Andrea Imparato17:10:01

hello! beginner question, is there a macro i can use to transform every binding in a let into defs?

andy.fingerhut17:10:30

Sure, the JVM JIT compilers are quite limited in the code sizes of methods that they can inline.

andy.fingerhut17:10:22

@imparato.andrea Nothing built into Clojure. I don't know of a 3rd party library that can do so, but my knowledge there isn't complete.

andy.fingerhut17:10:42

What leads you to want to do so, out of curiosity?

Andrea Imparato17:10:24

sometimes when i use the repl to debug i want to save the bindings in a let “automatically” so when i evaluate some code inside the let I have them. For example:

(let [a (f)
      b (g a)]
a)

Andrea Imparato17:10:51

if i want to evaluate (g a) i need to have a defined

noisesmith17:10:43

@imparato.andrea for a similar result (but not exactly what you asked for):

(ins)user=> (defmacro locals [] (into {} (map (juxt keyword identity) (keys &env))))
#'user/locals
(ins)user=> (let [a 0 b 1] (locals))
{:a 0, :b 1}
then you can add def to make the map visible globally

noisesmith17:10:08

if you are doing this for any reason other than debugging, I strongly suggest not doing so, and explicitly making def at the top level

noisesmith17:10:36

it makes code easier to understand, debug, and extend when the bindings are explicit and in expected places

noisesmith17:10:04

for debugging, combining locals as defined above with tap> is a great combo

👍 3
Andrea Imparato17:10:21

I’ll give it a try! thx!

Nassin17:10:39

so to my original question, how would I eval java.util.Date. in that example?

noisesmith17:10:11

eval exists, but it's generally better to avoid it (it's very expensive and can be a security issue to have it in an app)

andy.fingerhut17:10:01

There is a Java reflection API that you can pass strings to, and get back objects representing constructors, methods, fields, etc., and other methods that let you call such a constructor object, or method object.

noisesmith17:10:06

better to restructure so that you can eg. use a lambda #(java.util.Date.) which can be used as a proper value

noisesmith17:10:38

if you are constructing arbitrary classes, that's another thing that you might want to reconsider

Nassin17:10:07

thanks for the pointers

Cameron17:10:05

Yea, the thing is normally with something like (+ 1 2), evaluating this means evaluating each argument, resulting in (#function[x] 1 2), and then trying to apply the first argument (which is what we want after evaluation; the actual function, not a symbol) to the rest. But interop symbols like java.util.Date. don't actually evaluate to the method in question (and in fact, should throw some error on evaluation), so its actually defined as a sort of edge case where when evaluating a list like (java.util.Date.) , it will check to see if you're trying interop and then will just directly look up and use the proper java function right there (without using eval), rather than running the equivalent of (eval ..) on the symbol first and applying whatever comes out.

noisesmith17:10:08

@zdot101 they evaluate to invocation of a method, but on the jvm methods are not first class - the point is there's no "java function" to use, it's a property of an object, and you need to find and use that object

Cameron18:10:13

As long as its clear I'm not saying otherwise

Cameron18:10:18

Well, as I think on it and reread, there may be one detail I want to poke a bit and be sure we're on the same page (when I get back online I guess)

noisesmith18:10:11

@zdot101 I'm being a stickler about "function" because a key design aspect of clojure is the IFn / function abstraction, and the fact that jvm methods are not first class (they belong to an object and must be escorted by the object that owns them at all times), clojure solves this by making a special "function object" with an "invoke" method

noisesmith18:10:41

bringing it back to the initial example, #(java.util.Date.) creates a new function object of no args, whose invoke method instantiates a new date

Cameron18:10:42

Saying 'java function' is not meaning to make any implication that those functions themselves can be divorced from their class

noisesmith18:10:14

what I'm saying is that, especially in a #beginners channel, saying "function" for method is unhelpful - it erases a key distinction to understanding clojure

noisesmith18:10:34

and nowadays we have java.util.Function as well (doing something similar to what IFn does...)

Stuart19:10:03

https://vlaaad.github.io/reveal/#cursive I'm trying to understand this, can someone please help? It says > Create a “local repl” run configuration with “clojure.main” repl type, make it “Run with Deps” with remote-repl alias, and in Parameters specify -m vlaaad.remote-repl :port 5555. When I set my REPL up like this: If I choose clojure.main, it greys out run with deps and I get a Run Configuration Error ?

Stuart19:10:00

With those settings, the module drop down list is empty

Lennart Buit19:10:51

There is a #reveal, which is probably a directer way to get help 🙂

Stuart19:10:58

oh thanks!

noisesmith19:10:18

that or #cursive

Stuart19:10:37

man, clojure tooling is so confusing for beginners!

Frederik20:10:50

I want to use some typical lazy-sequence functions like take-while and reduce, but on short sequences ( < 32 ) where each element is computationally intensive. Is there a straight-forward way to avoid Clojure's chunking behaviour?

Frederik20:10:12

E.g. I want to use take-while on the output of a reduce and it's important that take-while stops exactly at the first element that returns negative, instead of automatically realizing the first 32 elements of the lazy sequence returned by reduce.

alexmiller20:10:42

reduce does not return a lazy seq

alexmiller20:10:35

if your goal is to reduce and stop during the reduce, you might want to consider either detecting and returning a reduced value inside the reduce, or using transduce with transducers and something like halt-when

alexmiller20:10:41

or use loop and exit without recurring

alexmiller20:10:48

(in general, if you care about chunking, you shouldn't be using lazy seqs)

Frederik20:10:45

Wrong assumption about the reduce, thanks for pointing that out! Putting it all together, think I'll just resort to the loop-recur option.