clojure

New to Clojure? Try the #beginners channel. Official docs: https://clojure.org/ Searchable message archives: https://clojurians-log.clojureverse.org/
jumar 2020-09-28T03:51:34.242100Z

A question regarding lazy-seq. I'm not sure why I cannot use conj instead of cons here:

(defn simple-range [i limit]
  (lazy-seq
   ;; nil returned by when will terminate the range construction
   (when (< i limit)
     (print ".")
     ;; notice you cannot use `conj` because get StackOverflowError in the `take 10` below
     (cons i (simple-range (inc i) limit)))))
(take 10 (simple-range 1 1e20))
;; => (1 2 3 4 5 6 7 8 9 10)

;; conj doesn't work
(defn simple-range2 [i limit]
  (lazy-seq
   ;; nil returned by when will terminate the range construction
   (when (< i limit)
     (print ".")
     ;; notice you cannot use `conj` because get StackOverflowError in the `take 10` below
     (conj (simple-range2 (inc i) limit) i))))
;; StackOverflowError
#_(take 10 (simple-range2 1 1e20))

phronmophobic 2020-09-28T03:58:22.242600Z

🤷 works for me

my.ns> (defn simple-range [i limit]
  (lazy-seq
   ;; nil returned by when will terminate the range construction
   (when (< i limit)
     (print ".")
     ;; notice you cannot use `conj` because get StackOverflowError in the `take 10` below
     (conj  (simple-range (inc i) limit) i))))
#'my.ns/simple-range
my.ns> (take 10 (simple-range 0 10))
..........(0 1 2 3 4 5 6 7 8 9)

phronmophobic 2020-09-28T04:00:26.243400Z

oops, nvmd. it overflows if the limit is really high

seancorfield 2020-09-28T04:07:42.244400Z

conj is implemented as coll.cons(x) so it's going to require that collection to be unwound far enough to cons that last element on.

seancorfield 2020-09-28T04:10:35.246100Z

conj is a collection function, rather than a sequence function -- and it's easier to think of those as eager whereas sequence functions are usually lazy (not accurate, but a reasonable heuristic)

takis_ 2020-09-28T10:58:41.250400Z

Hello 🙂 i have a dependency from github, i used https://github.com/reifyhealth/lein-git-down ,using the code from the Example of the project readme

takis_ 2020-09-28T11:00:11.252Z

classes are found,but it isnt working normally,i think exceptions happen,any help? or alternative way to do it ?

takis_ 2020-09-28T11:04:34.252500Z

i am using leiningen

p-himik 2020-09-28T11:19:38.252700Z

What exception? What dependency?

takis_ 2020-09-28T11:26:01.254900Z

i don't know it is handled from inside the code,the way i did it using that plugin , is the common way to do it using leiningen ?

takis_ 2020-09-28T11:26:48.255200Z

i try to use this

takis_ 2020-09-28T11:26:49.255400Z

https://github.com/sedmelluq/lavaplayer

takis_ 2020-09-28T11:27:11.255800Z

but from github not from maven

p-himik 2020-09-28T11:43:04.256800Z

But you say that it isn't working normally - how do you know that it isn't? What are the symptoms?

takis_ 2020-09-28T11:44:26.257800Z

its a music player,gets audio from youtube,but produces TrackExceptionEvent , when the maven same version doesnt

takis_ 2020-09-28T11:45:41.259100Z

but its working in general,other things from that code works,its the first time i used github dependency,and i dont know if lein-git-down is the right way to do it

takis_ 2020-09-28T11:48:10.259500Z

if the plugin is working ok,i guess its my fault somewhere

p-himik 2020-09-28T11:53:02.259900Z

Moving to a thread to avoid spamming the main channel. By "same version" you mean 1.3.50 and 60441fc5?

p-himik 2020-09-28T11:53:38.260100Z

And does the TrackExceptionEvent have any stack trace that you could share?

takis_ 2020-09-28T12:02:08.260300Z

On maven i use this

takis_ 2020-09-28T12:02:31.260700Z

on github the same is this i think

takis_ 2020-09-28T12:05:18.261100Z

my project.clj looks like

takis_ 2020-09-28T12:06:03.261300Z

(defproject test-project "0.1.0"
    :description "A test project"

    :plugins [[reifyhealth/lein-git-down "0.3.7"]]
    :middleware [lein-git-down.plugin/inject-properties]
    :dependencies [[lavaplayer "60441fc5a4f58e80a5466fa36b9366fb8501a8f5"]]
    :repositories [["jcenter-bintray" "<https://jcenter.bintray.com/>"]
                 ["bintray-rotate" "<https://dl.bintray.com/sedmelluq/com.sedmelluq>"]
                 ["public-github" {:url "<git://github.com>"}]
                 ["private-github" {:url "<git://github.com>" :protocol :ssh}]]
    :git-down {lavaplayer {:coordinates sedmelluq/lavaplayer}})

takis_ 2020-09-28T12:07:39.261500Z

i dont have the stack trace,i dont know how to get it, i get an Event object,that is made from that Exception handler i guess

p-himik 2020-09-28T12:09:53.261800Z

When you see that TrackExceptionEvent string somewhere - can you share a screenshot?

p-himik 2020-09-28T12:12:34.262Z

The probability of it being an issue with lein-git-down is quite high IMO because lavaplayer has not only Java code that can already be tricky with Git dependencies, but also native C code that's much more trickier.

takis_ 2020-09-28T12:21:00.262200Z

still i didnt found the stacktrace,but i found the Exception

takis_ 2020-09-28T12:21:03.262400Z

com.sedmelluq.discord.lavaplayer.player.event.TrackExceptionEvent "com.sedmelluq.discord.lavaplayer.tools.FriendlyException: Something broke when playing the track."

takis_ 2020-09-28T12:22:42.262600Z

its the first time i used github dependency,how people do it?

takis_ 2020-09-28T12:23:29.262800Z

i saw the deps.edn new cli , i dont know , but never used it,only leiningen i used

p-himik 2020-09-28T12:24:11.263Z

"FriendlyException", ha! - with a completely unfriendly message. Says absolutely nothing.

takis_ 2020-09-28T12:24:16.263200Z

thank you for helping me,its not so important thing, but its usefull to know how to use github dependencies in general

p-himik 2020-09-28T12:25:10.263400Z

Git dependencies are hard. Deps CLI will not help you here as it's designed to work with the dependencies that don't need any compilation - you can't even have Java files if you don't have precompiled class files for them.

takis_ 2020-09-28T12:26:16.263600Z

how to use a java project from github? even in local way

p-himik 2020-09-28T12:26:41.263800Z

I couldn't find any build instructions for lavaplayer. Potentially, the maintainers can do anything before they publish the jar to the Maven repository. But even if there were some build instructions, there's no tool out there that would be able to follow them automatically.

takis_ 2020-09-28T12:27:06.264Z

anyway its ok , i will leave it for now , thank you for helping me

takis_ 2020-09-28T12:27:44.264200Z

i will check it again sometime 🙂

p-himik 2020-09-28T12:28:44.264400Z

With regular Java and regular build steps, such tools like lein-git-down should indeed help. You can also have such a dependency not as a regular jar dependency but as vendored sources in your project - just as if it was part of your project. But don't do that unless you need to modify the sources of the dependency.

p-himik 2020-09-28T12:29:29.264600Z

No problem, HPH.

takis_ 2020-09-28T12:29:54.264800Z

yeah lein-git-down seems to work,maybe that lavaplayer is exception , thank you 🙂

victorb 2020-09-28T15:25:48.266600Z

anyone got any dns libraries laying around/to recommend? Been using https://github.com/brweber2/clj-dns but recently started using java 11 and seems *sun*.*net*.*spi*.*nameservice*.*NameServiceDescriptor* doesn't exist since Java 9, so no longer works. Interested in doing lookups of TXT records only

jsn 2020-09-28T15:32:58.266900Z

Something like https://docs.oracle.com/javase/7/docs/technotes/guides/jndi/jndi-dns.html via java interop, perhaps?

victorb 2020-09-28T15:37:32.267100Z

Thanks @jason358, yeah, by the description it seems like it'll do the trick, trying to figure out how to actually use it (never done any serious Java programming)

victorb 2020-09-28T15:39:16.267300Z

seems to have the most cumbersome API I've seen in the Java world, but I haven't seen too much of it so.

jsn 2020-09-28T15:50:44.267500Z

(-&gt; (javax.naming.directory.InitialDirContext.) (.getAttributes "<dns://ns-246-b.gandi.net/ice-9.eu>") (.get "TXT")) seems to work for me

jsn 2020-09-28T15:51:30.267700Z

or even (-&gt; (javax.naming.directory.InitialDirContext.) (.getAttributes "dns:///ice-9.eu") (.get "TXT")) , actually

victorb 2020-09-28T15:52:09.267900Z

It does indeed. I had just got half-way through the docs and even further from understanding. Still not sure how naming.directory comes to do DNS resolution, would expect that to be in some of the networking parts of Java

victorb 2020-09-28T15:52:19.268100Z

anyways, you're a hero @jason358, thanks a lot for helping out

victorb 2020-09-28T16:07:51.268300Z

for future reference, lazy wrapper to collect the record values as strings:

(defn txt-records [domain]
  (let [results (atom [])
        query-res
        (-&gt; (javax.naming.directory.InitialDirContext.)
            (.getAttributes (str "<dns://9.9.9.9/>" domain))
            (.get "TXT"))
        enum (.getAll query-res)]
    (while (.hasMore enum)
      (swap! results conj (.next enum)))
    @results))

jsn 2020-09-28T18:00:41.268500Z

(-&gt; (javax.naming.directory.InitialDirContext.) (.getAttributes "<dns://9.9.9.9/ice-9.eu>") (.get "txt") .getAll enumeration-seq) ?

vlaaad 2020-09-28T20:04:10.270Z

hmm, ho do I do map if every item in a result coll depends on a previous one?

Saikyun 2020-10-14T09:28:20.447900Z

aha, very cool. thanks!

vlaaad 2020-09-28T20:04:33.270400Z

e.g. there is a "state" that is accumulated while mapping

alexmiller 2020-09-28T20:04:45.271Z

you use reduce

vlaaad 2020-09-28T20:04:53.271200Z

but the result is always the same length as initial coll

alexmiller 2020-09-28T20:05:02.271500Z

So?

vlaaad 2020-09-28T20:05:09.271800Z

I was thinking there could be a lazy way to do that

alexmiller 2020-09-28T20:05:24.272200Z

iterate

vlaaad 2020-09-28T20:05:54.272900Z

but iterate is on a single value, and it's infinite

vlaaad 2020-09-28T20:06:30.273400Z

while my result is finite

vlaaad 2020-09-28T20:06:46.273800Z

I'll just use reduce I guess

ghadi 2020-09-28T20:08:04.274300Z

@vlaaad see the function on https://clojure.atlassian.net/browse/CLJ-2555

ghadi 2020-09-28T20:08:14.274600Z

iteration

vlaaad 2020-09-28T20:10:26.275300Z

but there is no side effects in my case

ghadi 2020-09-28T20:11:20.276400Z

then iterate will work fine

vlaaad 2020-09-28T20:11:23.276600Z

it's a map with some intermediate state calculated from inputs that has to be updated and read on each step

vlaaad 2020-09-28T20:18:01.277900Z

I just find it a bit strange that the thing I want to think of as a "map with accumulated state" turns into this big chunk of code:

(:acc
  (reduce
    (fn [{:keys [state acc]} [dt [event n]]]
      (let [state (case event
                    :price (assoc state :last-price n)
                    :div (update state :stock + (* (:stock state) (/ n (:last-price state)))))]
        {:state state
         :acc (conj acc [dt state])}))
    {:state {:stock 1 :last-price 0}
     :acc []}
    (sorted-map ;; example input
      0 [:price 10]
      1 [:div 1]
      2 [:price 20]
      3 [:div 2])))

emccue 2020-09-28T20:29:19.278600Z

be careful with anything under the javax package

emccue 2020-09-28T20:29:59.278800Z

I think there is actually a licensing violation if you ship software using that package name with classes not provided by oracle (or something like that)

emccue 2020-09-28T20:30:58.279Z

https://github.com/google/guava/issues/2960

emccue 2020-09-28T20:46:16.286200Z

(defn running-total-of-price [price-points]
  (loop [price-points (seq price-points)
         state {:stock 1 :last-price 0}
         price-history []]
    (if (empty? price-points)
      {:state state :acc price-history}
      (let [[dt [event n]] (first price-points)
            new-state (case event
                         :price (assoc state :last-price n)
                         :div (update state 
                                      :stock
                                      +
                                      (* (:stock state) 
                                         (/ n (:last-price state)))))]
        (recur (rest price-points)
                new-state
                (conj price-history [dt state]))))))

emccue 2020-09-28T20:46:55.286700Z

the way we learned map in school was just "recursion with linked lists"

emccue 2020-09-28T20:47:30.287500Z

so writing if empty? ... else (recur ... ) stuff is maybe more readable to me than it should be

emccue 2020-09-28T20:47:45.287900Z

but at least I can parse it better than the equivalent reduce

emccue 2020-09-28T20:48:15.288200Z

I don't know if thats helpful or not

victorb 2020-09-28T20:58:56.288500Z

eh, interesting and very annoying. Thanks for the headsup @emccue

jsn 2020-09-28T21:03:58.288700Z

Why is that annoying, why would you want to ship any class names under javax. not provided by Oracle (and how does that relate to the dns lookup code above, exactly)?

jsn 2020-09-28T21:06:14.288900Z

@victorbjelkholm429 did you see that you don't need atom and the imperative stuff?

Ben Sless 2020-09-28T21:10:05.289200Z

reductions?

2020-09-28T21:25:21.289400Z

@vlaaad I've been messing with this for that type of thing: https://gist.github.com/jjttjj/c0acfb066c4d58bbb823501a9ffc0687

2020-09-28T21:25:46.289600Z

If you're just interested in the previous item you could do

(defn map-prev
  ([f]
   (fn [rf]
     (let [vold (volatile! nil)]
       (fn
         ([] (rf))
         ([result] (rf result))
         ([result x]
          (let [old @vold
                new
                (if (some? old)
                  (vswap! vold f x)
                  (vreset! vold x))]
            (rf result new)))))))
  ([f xs]
   (map f xs (rest xs))))

2020-09-28T21:26:02.289800Z

(I've been focusing more on the transducer versions)

vlaaad 2020-09-28T21:26:52.290Z

thanks @jjttjj

vlaaad 2020-09-28T21:27:24.290300Z

Yeah, using mutable volatile is a fine option for single-threaded processing!

2020-09-28T21:27:30.290500Z

note with that map-prev nil is not a valid value, and it just sets the previous state the first time it sees a value.

2020-09-28T21:27:50.290700Z

but otherwise it's like map but the function you pass it just takes [old new]

vlaaad 2020-09-28T21:28:12.291100Z

agree on readability @emccue

vlaaad 2020-09-28T21:31:28.291300Z

hmm, looks like what I need

vlaaad 2020-09-28T21:36:57.291500Z

thank you!

🙂 1
jeaye 2020-09-28T22:31:24.293500Z

Is there any recommended way to get jsonista to losslessly encode keyword values so this returns equivalent data?

user=&gt; (-&gt; (j/write-value-as-string {:system/status :status/good} json-mapper) (j/read-value json-mapper))
#:system{:status "status/good"}
Transit+json does the job fine, but it's much slower.

emccue 2020-09-28T22:59:35.294400Z

@jeaye conceptually, for it to work regardless of your data format you need to "tag" keywords where-ever they appear

emccue 2020-09-28T22:59:45.294700Z

(separate from the library)

emccue 2020-09-28T23:00:17.295400Z

but also because keywords can appear as keys in maps, you need to manipulate the json structure quite a bit to losslessly encode and decode

emccue 2020-09-28T23:01:11.296Z

What you could do though, if you are feeling kinda lazy, is just put a prefix

emccue 2020-09-28T23:01:22.296300Z

so make a custom object mapper to give to the library

emccue 2020-09-28T23:01:28.296500Z

that when it encounters a keyword

emccue 2020-09-28T23:01:32.296800Z

instead of mapping it to

emccue 2020-09-28T23:01:43.297100Z

:some-keyword => "some-keyword"

emccue 2020-09-28T23:01:56.297300Z

do

emccue 2020-09-28T23:02:13.297700Z

:some-keyword => "💩some-keyword"

emccue 2020-09-28T23:02:24.298Z

and just look for the prefix when round tripping

emccue 2020-09-28T23:03:18.298900Z

as a consequence you might need to filter the poop emoji out from user input

emccue 2020-09-28T23:03:53.300Z

(transit gives the "right" answer, but there are tons of hacky ones like this)

jeaye 2020-09-28T23:03:57.300200Z

Yeah, I've considered that approach. I was hoping for something less clunky, but it may not exist.

emccue 2020-09-28T23:04:32.300400Z

yeah if you want this

emccue 2020-09-28T23:05:02.301100Z

{"a" :abc :def "hijklmnop"}

emccue 2020-09-28T23:05:40.302Z

to round trip correctly, you would have better luck just figuring out how to speed up the transit library to match your needs

emccue 2020-09-28T23:07:08.302600Z

well, the issue with maps is just that they always require string keys in the json repr

emccue 2020-09-28T23:07:32.303200Z

so in your own does-kinda-the-same-as-transit-but-not you can

emccue 2020-09-28T23:09:31.305400Z

:a =&gt; ["k", "a"]
"a" =&gt; ["s", "a"]
{:a 2} =&gt; ["m", ["k", "a"], 2]
{:a 2} =&gt; ["m", ["s", "a"], 2]
[:a 2] =&gt; ["v", ["k", "a"], 2]
#{:a} =&gt; ["@", ["k", "a"]]

emccue 2020-09-28T23:09:51.305900Z

always box everything

emccue 2020-09-28T23:10:23.306100Z

or you can just use xml

emccue 2020-09-28T23:11:23.307500Z

&lt;map&gt;
  &lt;entry&gt; 
    &lt;key&gt; &lt;keyword value="a"&gt;&lt;/string&gt; &lt;/key&gt;
    &lt;value&gt; &lt;number value=3&gt;&lt;/number&gt; &lt;/value&gt;
  &lt;/entry&gt;
&lt;/map&gt;

emccue 2020-09-28T23:11:42.307800Z

or just use edn and give up

emccue 2020-09-28T23:11:50.308100Z

{:a 3}

cfleming 2020-09-28T23:20:07.309Z

This is driving me nuts - either I’m doing something very stupid and I’m too tired to see it, or I’m misunderstanding something subtle:

(def common-errors #{{:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}}
                     {:unexpected :include-macros, :expected #{":as" ":only" ":refer" ":rename" ":exclude" :eof}}})
=&gt; #'user/common-errors
(-&gt;&gt; (take 5 errors)
     (remove (fn [error]
               (every? #(do (prn %)
                            (println (contains? common-errors %))
                            (contains? common-errors %))
                       (errors-from (:new error)))))
     (count))
{:unexpected :default, :expected #{":as" "sequential" ":only" ":refer" "symbol" ":rename" ":exclude" :eof}}
false
{:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}}
false
{:unexpected duration-inst, :expected #{"sequential"}}
false
{:unexpected :except, :expected #{":as" "sequential" ":only" ":refer" "symbol" ":rename" ":exclude" :eof}}
false
{:unexpected :include-macros, :expected #{":as" ":only" ":refer" ":rename" ":exclude" :eof}}
false
=&gt; 5
(contains? common-errors {:unexpected :except, :expected #{":only" ":rename" ":exclude" :eof}})
=&gt; true

cfleming 2020-09-28T23:21:14.310100Z

I have a common-errors set of error forms. I’m trying to filter those out of my list of errors. When I test a form manually against the set contains? returns true, but inside the remove it doesn’t.

cfleming 2020-09-28T23:22:25.310900Z

I’ve copy-pasted the manual test from the prned version, so it should be the same structure. There’s no metadata involved either.

2020-09-28T23:34:08.313100Z

when all else fails I like to capture the actual data, so I can check the types (eg. a symbol with a colon that prints like a keyword) - though it looks like you have that data and could just jump into checking that the printed values and assumed types match up

dpsutton 2020-09-28T23:34:28.313500Z

the second one in this list should have matched true? maybe chop down the the common-errors to just the first one and change it to equality rather than contains? and perhaps run it through data/diff. Is there any chance there's some shadowing going on here so common-errors isn't what you think it is?