beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Marcus 2020-11-04T10:16:41.165600Z

Is it possible to reload dependencies while in the repl? I have some local libraries installed in the .m2 directory and currently I have to restart the repl to use the latest version.

Daniel Stephens 2020-11-04T11:45:05.165900Z

haven't used it yet personally but I've heard some nice things about https://github.com/clj-commons/pomegranate to do this

Daniel Stephens 2020-11-04T11:46:35.166200Z

also for files that you have the source of, if you use cursive you can often just go to a file in the library, make your changes, and then evaluate the file.

Louis Kottmann 2020-11-04T12:10:11.166600Z

I've used pomegranate with success

Marcus 2020-11-04T12:49:19.168600Z

Thanks @dstephens! I will check it out. :)

👍 1
Marcus 2020-11-04T12:50:17.168800Z

I have not tested cursive yet but it looks interesting

Christian 2020-11-04T13:10:23.174400Z

Hi there, I'm doing the 4clojure problems to understand fp and clojure. I'm trying to count a sequence without using count. So my idea was to get the last element of the seq with last and then getting the last index of that element with last-element-of. so for '( 1 2 3 1) last should return 1 and the index should be 3. Count would be 3+1. But I can't get last-index-of to work: (fn newcount [x] (+ 1 (.last-index-of x (last x))))

mloughlin 2020-11-04T13:13:30.175100Z

Maybe I don't understand the question, but why would the last element's value be needed to count the seq?

dominem 2020-11-04T13:14:29.175200Z

Isn't reduce the answer in this case?

Christian 2020-11-04T13:15:58.176800Z

because that is my idea 😄 I'm not allowed to just use the count function. so that is what came to my mind as an alternative

Christian 2020-11-04T13:16:37.177Z

maybe, I don't know the reduce function. have to look that up. do you have an idea, why last-index-of is not working?

Thomas 2020-11-04T13:18:58.177200Z

You could try a recursive approach, the length of an empty sequence is 0, otherwise it’s 1 plus the length of the rest

mloughlin 2020-11-04T13:19:21.177400Z

If you're still getting the hang of functional programming, I would say: How would you do this in an imperative language?

mloughlin 2020-11-04T13:19:46.177600Z

Probably a for loop of some kind and an int that we increment in this case

dominem 2020-11-04T13:19:52.177800Z

Hint: Ask yourself what does (last seq) return. Hmm.. sorry, I just misinterpreted your code. I'll check in a moment :)

mloughlin 2020-11-04T13:20:40.178Z

in Clojure, the first things I think of when working with all of the items in a sequence is "Can this be done with map , filter or reduce? (in that order)"

👀 1
dominem 2020-11-04T13:24:10.178400Z

What is .last-index-of (note the dot - .)?

dominem 2020-11-04T13:24:55.178600Z

I only know https://clojuredocs.org/clojure.string/last-index-of (without the dot).

mloughlin 2020-11-04T13:25:03.178800Z

then if none of those fit the problem, a loop/`recur` will almost certainly do the trick

dominem 2020-11-04T13:26:19.179Z

:thumbsup: I like this way of thinking.

dominem 2020-11-04T13:27:41.179200Z

But there is .lastIndexOf:

user=> (def x '(1 2 3 1))
#'user/x
user=> (last x)
1
user=> (.last-index-of x (last x))
Execution error (IllegalArgumentException) at user/eval2007 (REPL:1).
No matching method last_index_of found taking 1 args for class clojure.lang.PersistentList

user=> (.lastIndexOf x (last x))
3
user=>

dominem 2020-11-04T13:29:45.179400Z

But I don't think this is the way you should solve this issue.

tugh 2020-11-04T13:52:05.180Z

@christiaaan there are 2 problems with your code. 1. as mentioned in the docs last-index-of only works on strings and you're not passing a string 2. dot notation is for interop(https://clojure.org/reference/java_interop#_the_dot_special_form) you can just (last-index-of [1 2 3] 1) notice that there is no dot in the beginning

Christian 2020-11-04T13:53:02.180600Z

interesting.... thank's for the pointers

Christian 2020-11-04T13:53:27.181200Z

what is interop?

dominem 2020-11-04T13:56:18.182Z

It's the mean you can *interop*erate with Java thanks to.

tugh 2020-11-04T13:56:42.182300Z

it is a mechanism to leverage libraries from the host environment. in clojure the host is jvm in clojurescript the host is js

Christian 2020-11-04T14:01:09.182700Z

okay, reduce did the trick. thanks everyone

1
dominem 2020-11-04T14:01:25.183Z

you're welcome 🙂

practicalli-john 2020-11-04T14:02:21.183700Z

One approach to this is to create a new sequence with a numeric value for each element in the original sequence, then sum the values in the new sequence.

Christian 2020-11-04T14:03:40.184700Z

I managed to solve it with reduce, pretty interesting way of doing things. @tugh thanks for explaining

✌️ 1
mloughlin 2020-11-04T14:05:16.186100Z

Can anyone think of a more concise way of writing this fn? It returns a property or nil depending on the value of another property in the same map

(defn nessus-id [entry]
  (let [plugin-id (get-in entry [:fields :plugin_id])]
    (when (and (= "nessus" (get-in entry [:fields :plugin]))
               plugin-id)
      plugin-id)))

practicalli-john 2020-11-04T14:10:19.186400Z

I think my favourite approach was map and reduce, using constantly to create the new seq. I did it lots of ways here... https://github.com/practicalli/four-clojure/blob/master/src/four_clojure/022_count_a_sequence.clj

mloughlin 2020-11-04T14:10:41.186700Z

I guess the and is unnecessary

mloughlin 2020-11-04T14:12:19.186900Z

and it follows that the let is also not needed 🙂

mloughlin 2020-11-04T14:13:30.187100Z

(defn nessus-id [entry]
  (when (= "nessus" (get-in entry [:fields :plugin]))
    (get-in entry [:fields :plugin_id])))

dominem 2020-11-04T14:25:05.188500Z

Just a bit simpler:

(defn nessus-id [entry]
  (let [pid (get-in entry [:fields :plugin_id])]
    (when (= pid "nessus") pid)))

mloughlin 2020-11-04T14:25:42.188800Z

my mistake, the "nessus" string is from :plugin not :plugin_id

dominem 2020-11-04T14:26:19.189Z

ahh, then it won't work my way

Jim Newton 2020-11-04T14:47:16.190900Z

I don't understand :post conditions for function definitions. I define a function as follows

(defn spec-to-rte 
  [pattern]
  {:post [(fn [v] (println [:spec-to-rte :returns v]) true)]}
 ...)
I can call the function and see its return value in the repl, but the println in the :post condition doesn't seem to be called, or at least its stdout is suppressed. Am I doing something obviously wrong?

2020-11-04T14:54:39.191300Z

You gave it an expression to evaluate, and it will evaluate it, returning a function, which is always logical true.

2020-11-04T14:54:45.191500Z

so not a useful postcondition.

Jim Newton 2020-11-04T14:55:12.191900Z

isn't the post condition called with the return value of the function?

Jim Newton 2020-11-04T14:57:12.192200Z

Here's the example in the documentation. https://clojure.org/reference/special_forms

2020-11-04T14:57:37.192900Z

Those are expressions that are evaluated, returning true or false.

2020-11-04T14:57:43.193300Z

Your expression, when evaluated, returns a function.

Jim Newton 2020-11-04T14:57:57.193800Z

the post condition doesn't return (> % 16) but rather calls it with the return value of the funciton. right?

2020-11-04T14:58:06.194100Z

every object/value in Clojure that is neither nil nor false is logical true.

Jim Newton 2020-11-04T14:58:38.195400Z

so in the documentation is (> % 16) always true?

2020-11-04T14:58:38.195500Z

% is replaced with the return value, at least in :post expressions, yes.

Darin Douglass 2020-11-04T14:58:51.195900Z

:pre/`:post` expand out into asserts that run before/after your body. the source is pretty enlightening with regards to that https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L4562

2020-11-04T14:59:18.196800Z

When you evaluate (> % 16) after replacing % with the return value, if that return value is such that evaluating (> % 16) does not throw an exception, then it will return true or false.

Jim Newton 2020-11-04T14:59:34.197100Z

ahh I thought (> % 16) was an anonymous function

Jim Newton 2020-11-04T14:59:50.197700Z

doesnt that have a very similar syntax?

2020-11-04T14:59:55.197900Z

It looks like one, but #(> % 16) is an anonymous function.

Jim Newton 2020-11-04T15:00:38.198400Z

ouch, that's really confusing. Am I the only one that was confused by that?

Darin Douglass 2020-11-04T15:01:29.199400Z

nope, i've personally never liked pre/post.

2020-11-04T15:02:45.200600Z

The Eastwood linter can catch many such silently-always-true :pre and :post conditions. It hasn't been updated in a while, but still works for a lot of Clojure/JVM code bases, I think (it does not support ClojureScript)

Jim Newton 2020-11-04T15:04:03.201700Z

wow looking at the source code is horrible. that means % is a hacky reserved variable in the post condition. If my code contains something like #(f % 12) it will do wierd things.

2020-11-04T15:05:18.203600Z

I suspect that the reader might handle % inside #( ... ) expressions before the :pre and :post handling code ever get to look at it, but not sure about that. It would be clearer not to include anonymous functions in :pre and :post expressions, for sure.

Jim Newton 2020-11-04T15:05:54.204300Z

why wan't this done in a functional way? if :post specified a sequence of functions which should be called and all return true. I could write something like {:post [even? pos?]} and with would be more consistent with the language? right?

Jim Newton 2020-11-04T15:06:04.204600Z

OK, it is what it is.

2020-11-04T15:06:28.204900Z

I did not design it, nor have I asked the designer why they chose that way.

Jim Newton 2020-11-04T15:07:23.206Z

OK, I changed it to

(defn spec-to-rte 
  [pattern]
  {:post [(do (println [:spec-to-rte :returns %]) %)]}
...)
and it works correctly. hurts my eyes to look at though

2020-11-04T15:07:27.206100Z

I am not trying to imply that such questions are useless, but some questions like that have well known design decisions that many in the Clojure community know, but some are much less well known, perhaps only to one person.

Jim Newton 2020-11-04T15:07:46.206300Z

yes you're right.

Jim Newton 2020-11-04T15:08:31.206600Z

important thing is that I understand now.

2020-11-04T15:09:48.208Z

Unit testing of such things is a good practice, e.g. in the REPL, especially the first time you use a new language construct. If you can't make a :post condition fail, even though you believe your condition should obviously be false, that is a sign that you are not using the correct expression there.

2020-11-04T15:11:47.208800Z

In your last version of the :post condition above, is your goal that there should be an assertion exception thrown if spec-to-rte returns nil or false? Because I believe that is what that code will do.

2020-11-04T15:13:13.209400Z

If you want run-time trace messages, there is a library called tools.trace that might also suit your needs: https://github.com/clojure/tools.trace

Jim Newton 2020-11-04T15:25:28.210200Z

ouch yes you're right. no, my intention is just to trace the result and don't assert anything.

Jim Newton 2020-11-04T15:25:31.210400Z

thanks

Jim Newton 2020-11-04T15:26:48.211Z

is there a better way to trace the input and output of a function than by using :pre and :post ?

2020-11-04T15:27:39.211200Z

I tried to mention one way above .... (see link to tools.trace library in my previous message -- not saying it will suit your needs, but that is exactly what that library is intended to help with)

Jim Newton 2020-11-04T15:34:27.212300Z

ahhh, thanks for the link. I hadn't read the end of your message because I was busy fixing the bug that the first half of your message pointed out.

Jim Newton 2020-11-04T15:34:28.212500Z

🙂

Darin Douglass 2020-11-04T15:37:34.214200Z

another options would be a logging library like mulog (https://github.com/BrunoBonacci/mulog)

Jim Newton 2020-11-04T15:37:36.214500Z

BTW, to use that trace library, I need to add something to my .lein/profiles.clj file. Is there a way to load the dependency [org.clojure/tools.trace "0.7.10"] without restarting?

Darin Douglass 2020-11-04T15:37:44.214800Z

mulog.core/trace has a way to capture output of fns into logs

Jim Newton 2020-11-04T15:38:42.215800Z

capturing into log files might be interesting, because sometimes my code redirects stdout by (binding [**out** ...] ...) and then tracing to stdout confuses everything.

2020-11-04T15:43:20.217900Z

I have heard people using some techniques to add libraries to your Java classpath without starting a new JVM, but I haven't used them or have any handy links explaining how. I tend to start a new JVM process when I add new libraries.

2020-11-04T15:44:33.219400Z

It should work to do git clone of the Clojure source code, and then do one or more load-file calls from a REPL session, with the full path to the source code, but you would have to do them in the order from "bottom up" so that require calls never needed to look for a source file in your class path. (this is a very tedious way to do it if there are many namespaces, and not recommended -- I only mention it because it is technically possible to do).

dharrigan 2020-11-04T15:44:35.219600Z

How might this be modelled in clojure?

dharrigan 2020-11-04T15:44:37.219800Z

(input.get() & 0xFF)
                | ((input.get() & 0xFF) << 8)
                | ((input.get() & 0xFF) << 16)
                | ((input.get() & 0xFF) << 24)

2020-11-04T15:47:22.220500Z

There are bit-and bit-or and bit-shift-left functions in Clojure that work pretty much like & | and <<

dharrigan 2020-11-04T15:47:36.220800Z

Yup, found those, it's just the application that would stump me

2020-11-04T15:49:39.221100Z

user=> (defn input-get []
  ;;; code here to emulate input.get()
  0x17
  )

#'user/input-get
user=> (def next-4-bytes-as-32bit-word
  (bit-or (bit-and (input-get) 0xff)
          (bit-shift-left (bit-and (input-get) 0xff) 8)
          (bit-shift-left (bit-and (input-get) 0xff) 16)
          (bit-shift-left (bit-and (input-get) 0xff) 24)))

#'user/next-4-bytes-as-32bit-word
user=> (format "%08x" next-4-bytes-as-32bit-word)

"17171717"

ghadi 2020-11-04T15:51:22.221700Z

you can also use a ByteBuffer's getInt method to swap the endianness

💯 1
ghadi 2020-11-04T15:51:48.222200Z

that's a standard pattern of reading 4 bytes and reconstructing a 32 byte integer

dharrigan 2020-11-04T15:52:28.222500Z

thank you both. Andy - studying... 🙂

2020-11-04T15:57:37.222700Z

I've used pomegranate to add deps, I didn't realize it could replace them

2020-11-04T16:00:50.222900Z

(defn nessus-id [{{:keys [plugin plugin_id]} :fields}] 
  (when (= plugin "nessus")  
    plugin_id))

jaihindhreddy 2020-11-04T16:00:52.223100Z

Perhaps https://clojure.org/guides/destructuring can help:

(defn nessus-id [{{:keys [plugin plugin_id]} :fields}]
  (when (and plugin_id (= plugin "nessus"))
    plugin_id))

2020-11-04T16:01:03.223300Z

jynx

1
jaihindhreddy 2020-11-04T16:01:04.223500Z

@noisesmith jinx!

jaihindhreddy 2020-11-04T16:02:48.223800Z

The two solutions above differ when plugin_id is false (and plugin is equal to "nessus"). Mine will return nil whereas noisesmith's will return false. Just something to be aware of.

mloughlin 2020-11-04T16:20:02.224100Z

nested destructuring doesnt have the most intuitive syntax

mloughlin 2020-11-04T16:20:36.224300Z

but besides that, I like it!

mloughlin 2020-11-04T16:21:02.224500Z

Time to re-read the destructuring docs

2020-11-04T16:22:58.224700Z

all that's used here: {foo :bar} - sets foo to the value under :bar in the map, {:keys [a b]} sets a,b to the values of :a :b in the map

2020-11-04T16:24:07.224900Z

bindings are on the left because map keys must be unique, so it restricts reuse of bindings instead of keys so you can use the same key multiple places

mloughlin 2020-11-04T16:29:56.225100Z

I see {:keys [a b]} all the time, not so often {foo :bar}

2020-11-04T16:52:41.225600Z

Hi all! I need help with video tip. We are five javascript developers that has set out to do a small project in clojurescript + node + express during a couple of meetups. Four of us have not written any clojure, and the fith not much, so our first meetup (4h) is planned to be an intro to clojure/clojurescript. It would be splendid if we could find some video with a primer on syntax, but primarily on the common data-collections and how to manipulate them. Not too long as everybody is eager to hop into the editor 🙂 Any tip would be gratefully received!

2020-11-04T17:42:47.225900Z

For videos, I have heard good reviews about Eric Normand's https://purelyfunctional.tv/ but I have not viewed them myself. He has been offering reduced rates during Covid lockdown time to those who are not able to pay, if you contact him personally. Even if you are able to pay but would like a free sample before deciding to purchase, I imagine he might consider such requests.

2020-11-04T18:17:21.227Z

There are some more here too: https://www.jacekschae.com/

dharrigan 2020-11-04T19:30:38.227400Z

that's great - just looked at the java api. wonderful!

dharrigan 2020-11-04T19:30:39.227600Z

thanks

Roger Amorin Vieira 2020-11-04T19:41:14.229200Z

Hi I have this string in a file: DÉBITO In the clojure after reading the file: DEB\ufffdTO Someone know how can I remove this special character?

dpsutton 2020-11-04T19:44:11.230Z

how are you reading the file?

Roger Amorin Vieira 2020-11-04T19:44:47.230400Z

(defn read-file
   [path]
   (with-open [rdr (<http://clojure.java.io/reader|clojure.java.io/reader> path)]
      (reduce conj [] (line-seq rdr))))

seancorfield 2020-11-04T19:45:30.231100Z

Are you sure it's not just the Unicode representation being shown when you print the value?

dpsutton 2020-11-04T19:45:34.231300Z

/t/stuff ❯❯❯ echo "DÉBITO" &gt; chars
/t/stuff ❯❯❯ clj
Clojure 1.10.1
user=&gt; (slurp "chars")
"DÉBITO\n"
user=&gt; (with-open [rdr (<http://clojure.java.io/reader|clojure.java.io/reader> "chars")] (into [] (line-seq rdr)))
["DÉBITO"]
user=&gt;

dpsutton 2020-11-04T19:47:28.232600Z

is there a default encoding for jvms?

walterl 2020-11-04T19:47:33.232700Z

What encoding was the file saved in?

Roger Amorin Vieira 2020-11-04T19:49:50.233900Z

It is an ofx file

ghadi 2020-11-04T19:49:54.234300Z

the original symptom is not clear you're reading a string DEBITO from DEPOSITO?

ghadi 2020-11-04T19:50:06.234600Z

need to re-evaluate your facts

ghadi 2020-11-04T19:50:22.235Z

P's don't turn into B's when you read them

ghadi 2020-11-04T19:50:46.235800Z

and I really hope that a debit doesn't turn into a deposit, and if it does, let me sign up for your bank please

Roger Amorin Vieira 2020-11-04T19:50:47.235900Z

Sorry I wrote wrong, is DEPOSITO and DEBITO the problem

ghadi 2020-11-04T19:51:17.236400Z

ok so what's the content of the file?

Roger Amorin Vieira 2020-11-04T19:51:36.236900Z

I have a function that remove special characters

(defn deaccent [str]
   "Remove accent from string"
   ;; <http://www.matt-reid.co.uk/blog_post.php?id=69>
   (let [normalized (java.text.Normalizer/normalize str java.text.Normalizer$Form/NFD)]
      (clojure.string/replace normalized #"\p{InCombiningDiacriticalMarks}+" "")))

ghadi 2020-11-04T19:51:39.237200Z

unicode fffd is a "unknown replacement character" meaning some sort of sadness already happened

👍 1
Roger Amorin Vieira 2020-11-04T19:52:05.237800Z

But in tests remove 100% the Ó but in the run dont, i thing is becaus of \

Roger Amorin Vieira 2020-11-04T19:52:31.238400Z

In my database I have this error when I try to submit the file Incorrect string value: '\xEF\xBF\xBDdit...' for column 'name' at row 1

walterl 2020-11-04T19:53:18.239400Z

\ufffd is often seen when trying to decode a Unicode string with an encoding other than the one the string was encoded in.

walterl 2020-11-04T19:53:52.240500Z

E.g. your file content is possibly encoded in latin-1, and you're trying to decode as utf-8

Roger Amorin Vieira 2020-11-04T19:54:20.241100Z

If I do (str/replace string #"\ufffd" "") might work?

Roger Amorin Vieira 2020-11-04T19:58:00.241800Z

Ye, works, thanks

dpsutton 2020-11-04T19:58:48.242600Z

i think you're papering over your problem. if you can identify why \ufffd characters (codepoints?) are ending up in your string you'll likely properly fix the underlying problem

ghadi 2020-11-04T19:59:25.242900Z

^^^

ghadi 2020-11-04T19:59:57.243800Z

check (System/getProperties "file.encoding") on both your local env, and your CI, and your server

ghadi 2020-11-04T20:00:20.244300Z

hopefully it's UTF-8 everywhere

ghadi 2020-11-04T20:00:31.244700Z

then whatever your database is needs to not mangle UTF-8

Roger Amorin Vieira 2020-11-04T20:04:02.246900Z

Yes, I will need to fix the origin of this issue

Roger Amorin Vieira 2020-11-04T20:05:13.247300Z

Thanks for all help, I will try what you told @ghadi

walterl 2020-11-04T20:06:47.247700Z

@contato509

; eval (current-form): (spit "foo.txt" "DÉBITO" :encoding "ISO_8859_1")
nil
; --------------------------------------------------------------------------------
; eval (current-form): (slurp "foo.txt")
"D�BITO"
; --------------------------------------------------------------------------------
; eval (current-form): (slurp "foo.txt" :encoding "ISO_8859_1")
"DÉBITO"

walterl 2020-11-04T20:09:24.248400Z

Related: TIL how to set encoding for writing/reading files :neckbeard:

Roger Amorin Vieira 2020-11-04T20:09:53.248700Z

@clojurians-slack100 works, thankss ❤️

2020-11-04T20:22:04.248800Z

Thanks! Will check it out 🙂

mbjarland 2020-11-04T21:08:14.251Z

quick question, I’m playing with clojure koans and have the following code:

(ns binary-search)

(defn middle [coll]
  (quot (count coll) 2))

(defn search-for
  [x coll]
  (when (empty? coll) (throw (RuntimeException. "not found")))
  (let [i (middle coll)
        c (nth coll i)]
    (cond
      (= c x) i
      (&gt; c x) (search-for x (take i coll))
      (&lt; c x) (+ i 1 (search-for x (drop (inc i) coll))))))
which does binary search in a coll. What I don’t understand is, why does the following not blow the stack?
(search-for 9999999 (range 10000000))
=&gt; 9999999
As I am not using recur, I figured this should be toast. JVM doing TCO even without recur? Also printed the stack at around 100 000 and it is very shallow. [the rest of the code is really irrelevant, I’m trying to understand why a self recursive function doesn’t blow the stack after 100k recursive calls].

agile_geek 2020-11-05T11:14:30.253900Z

Also even tho not using recur you are not holding on to the head of the collection so the collection discarded is garbage collected.

phronmophobic 2020-11-04T21:12:41.251400Z

if it's dividing the search coll in half every iteration, it should only do ceil(log2(10000000)) = 24 recursive calls max, right?

2020-11-04T22:00:07.252Z

range also has some tricks up its sleave

2020-11-04T22:00:40.252200Z

user=&gt; (type (range 1000))
clojure.lang.LongRange
user=&gt; (supers clojure.lang.LongRange)
#{clojure.lang.IPersistentCollection java.io.Serializable clojure.lang.ASeq clojure.lang.IChunkedSeq clojure.lang.Counted clojure.lang.IMeta clojure.lang.Obj clojure.lang.IHashEq clojure.lang.Seqable clojure.lang.ISeq java.lang.Iterable clojure.lang.IReduceInit java.util.Collection clojure.lang.IObj java.util.List java.lang.Object clojure.lang.Sequential clojure.lang.IReduce}
user=&gt;