Fork me on GitHub
#beginners
<
2018-03-20
>
ghadi01:03:39

Good problem for this room ^

ghadi01:03:30

the asker specified using a particular libary (Joda-Time) but the only library you need nowadays (since 2014) is baked into the JVM (the java.time.* package) You don't even need a "clojure library" to wrap it. But you have to get comfy calling Java objects (really not very different than Ruby or Python)

ghadi01:03:10

one way to do it is like so:

(import (java.time LocalDate DayOfWeek))

(let [starting-at (LocalDate/of 2018 3 1)

      days (iterate #(.plusDays % 1) starting-at)

      mondays (filter (fn [day]
                        (= DayOfWeek/MONDAY (.getDayOfWeek day)))
                      days)]
  (str (nth mondays 2)))

ghadi01:03:34

nothing gross about mixing Java interop with Clojure sequences

seancorfield01:03:31

I was just writing it up using clj-time (since the OP asked about Joda Time) and, yeah, I was arriving at the same solution 🙂

seancorfield01:03:07

(! 770)-> clj -Sdeps '{:deps {clj-time {:mvn/version "RELEASE"}}}'
Clojure 1.9.0
user=> (require '[clj-time.core :as t] '[clj-time.predicates :as p])
nil
user=> (nth (->> (t/date-time 2018 3 1) (iterate #(t/plus % (t/days 1))) (filter p/monday?)) 2)
#object[org.joda.time.DateTime 0x771158fb "2018-03-19T00:00:00.000Z"]
user=> (str *1)
"2018-03-19T00:00:00.000Z"

seancorfield01:03:57

Or using clojure.java-time (a very thin wrapper for Java Time):

(! 772)-> clj -Sdeps '{:deps {clojure.java-time {:mvn/version "RELEASE"}}}'
Clojure 1.9.0
user=> (require '[java-time :as jt])
nil
user=> (nth (->> (jt/local-date-time 2018 3 1) (iterate #(jt/plus % (jt/days 1))) (filter jt/monday?)) 2)
#object[java.time.LocalDateTime 0x1983b48a "2018-03-19T00:00"]
user=> (str *1)
"2018-03-19T00:00"

ghadi02:03:22

@seancorfield I'm mildly surprised that jt/local-date-time takes a 3-argument constructor that only specifies date and not any time.

ghadi02:03:00

The underlying constructor in the java library does not offer that arity

brunobraga02:03:15

so, I am trying to remove every new line from a file that I reading using slurp..the way I am trying to remove the new lines is like this: (print (apply str (filter #(not (#{\newline} %)) string))) it words for a small string, but for some reason when I try it over the whole file, it returns something weird, which is pretty much a line in te middle kind of

brunobraga02:03:26

can anyone see something weird about this function?

seancorfield02:03:30

@brnbraga95 Since slurp gives you the entire file as a string, a simple string replacement would be a lot more efficient than converting the data to a sequence, filtering it, and squashing it back into a string.

Russ Olsen03:03:22

@brnbraga95 So I agree with @seancorfield that something like (.replace string "\n" "") is the way to go, but I'm also not sure why your aren't getting the result you're expecting from your original way. Is it possible there is a carriage return or some other odd character in the file?

brunobraga03:03:41

it could be that, I indeed changed my approach to read line by line, so that I can work with large files as well

mping11:03:45

Hi all, can anyone explain to me why commute is called twice? I understand the difference between alter and commute but I don’t know why commute is called at the beginning and at commit point

jumar11:03:48

When you use commute you state that "changes may have been made by other transactions to any Refs that have been commuted by this transaction". The second call is to ensure that a proper updated value is commited if the other transaction updated it while your transaction was running. Otherwise you might get only one update applied although there were two updates actually. alter will solve this situation by retrying the whole transaction whereas commute relies on "commutatitivy" of the update fn and can give you better performance.

mping17:03:34

@U06BE1L6T but what does commute do with the first value? I dont get why the 2nd commute alone isn’t sufficient

jumar17:03:00

that's because you want to have the new value available inside your transaction

mping17:03:00

what does clojure do with the result of the 1st commute ? I looked into the java source and didn’t get it…

mping17:03:37

I also read the SO post but it still doesn’t make alot of sense

jumar17:03:17

I'm not an expert, but I believe that's because you actually want to access the updated value inside your transaction 🙂

mping17:03:25

so, 1st commute generates an updated value, and the 2nd updates at commit point?

mping17:03:28

:thinking_face: that would imply that the value I write may not be the value that is set?

sarna11:03:42

I'm having some troubles using boot. I've used this guide https://lionfacelemonface.wordpress.com/2015/01/17/boot-getting-started-with-clojure-in-10-minutes/ when I tried to run boot build it said jar has been created, yet I see no jars in my directory

rauh11:03:18

@mailmeupinside not a boot guy myself, but have you looked itno ./target/ dir?

sarna11:03:51

@rauh there's no ./target

sarna11:03:31

it's like boot didn't run at all :thinking_face:

sundarj12:03:13

@mailmeupinside boot doesn't write any files by default unless you run the target task afterwards

sundarj12:03:17

so boot build target should do the trick

sarna12:03:14

@sundarj it works! thanks a bunch

sarna12:03:38

I have another problem now 😄

(clojure.string/split "foo bar" #" ") ; works
(clojure.string/split ["foo bar" "x y"] #" ") ; obviously doesn't
(apply clojure.string/split ["foo bar" "x y"] #" ") ; also doesn't but I don't know why

sundarj12:03:29

apply is for taking the arguments from a collection and applying a function to them, like (apply + [1 2])

sarna12:03:32

ah. I wanted something like Haskell's fmap

sundarj12:03:32

=> (apply clojure.string/split ["foo bar" #" "])
["foo" "bar"]

sarna12:03:50

to go "inside" that collection

sundarj12:03:09

that's map in Clojure

sarna12:03:26

:face_palm: thanks

sundarj12:03:58

@mailmeupinside

=> (map (fn [s] (clojure.string/split s #" ")) ["foo bar" "x y"])
(["foo" "bar"] ["x" "y"])

sundarj12:03:10

and if you want all the results in a single collection, use mapcat instead of map

sundarj12:03:24

=> (mapcat (fn [s] (clojure.string/split s #" ")) ["foo bar" "x y"])
("foo" "bar" "x" "y")

sundarj12:03:44

no prob 🙂

grierson14:03:49

Is there anything like NCruch or Wallaby.js for Clojure? I know there is 'Lein auto test' but is there a plugin were the results appearing withing the editor next to the line with a Green tick or Red cross?

Alex Miller (Clojure team)15:03:41

Cursive will do this if you’re using clojure.test

grierson15:03:24

Thanks! Might need to starting using Cursive. Does Cursive have inline evaluation? Does it update the inline evaluation and test as you type?

Alex Miller (Clojure team)15:03:56

you can eval expressions in your editor and send them to your repl if that’s what you mean

grierson15:03:43

Yes. That's great thank you.

pawel.kapala15:03:49

Could anyone give me a hand finding discrepancy with clob in jdbc? When I run the same query against h2 and posrgresql I get two different results:

(jdbc/query db ["SELECT bar FROM foo"])
for postgre returns:
({:bar "fapfap"})
and for h2 returns:
({:bar #object[org.h2.jdbc.JdbcClob 0x7844d931 "clob7: 'fapfap'"]})
Why is that? I’d expect same thing to be returned in both cases. If it’s driver specific, how exactly clob is actually accessed in clojure.java.jdbc? Tried reading code, but struggling to find the right spot, where it is actually read from ResultSet, somewhere around: https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc.clj#L1092 Thanks!

pawel.kapala16:03:31

For reference, I solved it by passing :read-columns that supports org.h2.jdbc.JdbcClob, based pretty much on internal implementation: https://github.com/clojure/java.jdbc/blob/master/src/main/clojure/clojure/java/jdbc.clj#L442

pawel.kapala20:03:17

Actually you can do less than that, and just extend the protocol:

(extend-protocol jdbc/IResultSetReadColumn
         JdbcClob
         (result-set-read-column [x _2 _3] (slurp (.getCharacterStream x))))

sarna16:03:06

hey, how do I map three levels deep? 😅 I have something like [[["foo" "bar"]]] and I have to map over foo and bar

alexk16:03:49

it would depend on how invariant that structure/depth is

alexk16:03:22

it is a case of “iterate the most highly nested collection”, or “iterate through the first of the first item”?

sarna16:03:36

((["abcde" "fghij"]) (["abcde" "ecdab"] ["xyz" "ers" "sew"])) would be a sample seq from my code I have to do something for every string

alexk16:03:13

One approach: (map (fn [s] ___) (apply concat (map first input)))

schmee16:03:40

Specter can help:

user=> a
((["abcde" "fghij"]) (["abcde" "ecdab"] ["xyz" "ers" "sew"]))
user=> (transform [ALL ALL ALL] count a)
(([5 5]) ([5 5] [3 3 3]))

sarna16:03:38

I'm doing it in a ->> macro, which complicates stuff a bit 😅

sarna16:03:08

with two levels I could get away with (map #(map seq %) foo) but now it's harder

sarna16:03:52

I think something like specter is going to be necessary if I want it to be any readable

sarna16:03:02

thanks for help 🙂

ghadi16:03:48

let's not suggest Specter for beginners

ghadi16:03:02

best to learn the fundamentals of the core library

joelsanchez16:03:05

specter is never a necessity, and only sometimes a convenience

orestis16:03:21

Obligatory: “Perhaps you should revisit the data structure?” not-very-helpful suggestion 🙂

joelsanchez16:03:39

also, in this case the answer can't be easier given (def a '((["abcde" "fghij"]) (["abcde" "ecdab"] ["xyz" "ers" "sew"]))) you just (flatten a) ... try (map count (flatten a))

sarna18:03:01

ah yeah, flatten! that's the function I've been looking for, thanks :D

felipebarros17:03:40

Does anybody know of a library for CLJ/CLJS that has the same intention as How to Design Program's https://docs.racket-lang.org/teachpack/2htdpimage.html ?

felipebarros17:03:20

Seems to be really interesting but too different from htdp2/image. I wanted something to draw that included a lot of ready functions like star and polygon with overlays. The idea is not to follow the book with Clojure rather than Racket but to play here and there with how it would look like in the Clojure world.

felipebarros17:03:32

Thank you though!

Russ Olsen17:03:46

Sure! It wouldn't surprise me if there is other things out there -- certainly you could do it all with Java interop -- but probably not what you are looking for.

felipebarros17:03:56

@U9H7B8P7X I just remembered there is a Clojure/ClojureScript library for compiling Processing/p5.js and although it has a focus on animation, I guess it will do what I need http://quil.info/api 🎉

schmee17:03:14

oops, didn't realize this was #beginners, in that case specter should wait 🙂

schmee17:03:28

@joelsanchez that can be said about anything that isn't assembly

joelsanchez17:03:34

specter isn't always better in terms of readability, which can't be said when comparing C to assembly

joelsanchez17:03:48

in this example, flatten vs transform [ALL ALL ALL]

schmee17:03:12

they don't do the same thing, so it's not a fair comparison

schmee17:03:30

specter retains the original structure while flatten doesn't

schmee17:03:49

if it's not necessary to do that, the flatten version is of course preferable

joelsanchez17:03:16

that's true, yep

timo17:03:54

Hi there, does anyone know how I can change javascripts this from cljs? (goog.object/set this "value" "foobar") does not work...

joelsanchez17:03:36

there's this-as and (js-this), you choose

joelsanchez17:03:04

(this-as this
  (goog.object/set this "value" "foobar"))

(goog.object/set (js-this) "value" "foobar")

joelsanchez17:03:16

bear in mind that function literals and partial won't retain this context

Kent17:03:51

Any tips or example projects for building real-time systems with Clojure and PostgreSQL? I am looking to build a realtime app with Clojure and Postgresql using NOTIFY, LISTEN, and UNLISTEN with triggers. I am using the driver here: https://github.com/alaisi/postgres-async-driver

jumar07:03:48

Not answering your question but this might be interesting: the myth of asynchronous JDBC: http://mikemainguy.blogspot.cz/2015/05/the-myth-of-asynchronous-jdbc.html

gklijs07:03:01

I'm trying out postgres now, replacing an atom with the database. It's a bank emulation, doing transactions. With the atom, I could easily handle 10.000 transactions a second, now it's down to about 100. I'm using the same library, and some pointers from http://lacinia.readthedocs.io/en/latest/tutorial/database-1.html

jonrob18:03:26

What's the idiomatic way to extract content from deep inside a json object? e.g. { 'results': [ { 'entries': [ { 'features': [ 'a', 'b' ] }, { 'features': ['c', 'd'] ] } ] } <- I'd like to extract 'a', 'b', 'c' and 'd'

greglook18:03:29

(->> (get-in data ["results" 0 "entries"]) (mapcat (fn [entry] (get entry "features")))) => ("a" "b" "c" "d")

jonrob18:03:29

@greg316 - thanks - what if there were multiple elements in results? e.g. i didn't want just index 0 or results?

greglook18:03:54

similar idea then - you’d be mapping over (get data "results") instead

jonrob18:03:12

right, so you'd nest the maps?

greglook18:03:22

(->> (get data "results") (mapcat (fn [result] (mapcat (fn [entry] (get entry "features")) (get result "entries"))))

greglook18:03:50

or you can nest less and do more pipelining if you prefer

greglook18:03:57

depends on how much context you want to preserve

jonrob18:03:31

sorry, but new to this, but by 'more pipelining' do you mean extract some of the nested calls to their own functions?

sarna19:03:26

what do you typically use to construct a data structure? reduce? I want to create a map that would have a letter as a key and how many these letters I've found as a value

val_waeselynck20:03:40

Check out the source code of frequencies

sarna21:03:27

alright, thank you

sundarj21:03:01

@mailmeupinside if you weren't aware, you can do so by typing (source frequencies) into a repl

sarna21:03:07

@sundarj you're a godsend 🙏

sundarj21:03:23

the rest of the functions in clojure.repl are handy too: https://clojuredocs.org/clojure.repl 🙂

sarna21:03:27

great :^)

sundarj19:03:46

that sounds like a reduce to me

sundarj19:03:44

although maybe the frequencies function does what you want (it is implemented with reduce)?

sarna21:03:13

thanks 👍

lum22:03:20

(defn un-frequencies-helper [a-map a-seq]
  (if (empty? a-map)
    (reverse a-seq)
    (let [fst-key ((first a-map) 0)
          fst-val ((first a-map) 1)]
      (if (<= fst-val 1)
        (un-frequencies-helper (rest a-map) (cons fst-val a-seq))
        (un-frequencies-helper (assoc a-map fst-key (dec fst-val))))
      (un-frequencies-helper a-map (cons fst-key a-seq)))))

lum22:03:58

(defn un-frequencies [a-map]
             (un-frequencies-helper a-map '()))

lum22:03:58

(un-frequencies {:a 3 :b 2 "^_^" 1})
clojure.lang.ArityException: Wrong number of args (1) passed to: recursion/un-frequencies-helper

lum22:03:15

hi, where is my error?

sundarj22:03:57

@lum you're only passing one argument to un-frequencies-helper here: (un-frequencies-helper (assoc a-map fst-key (dec fst-val)))

lum22:03:54

ah, fine, thought there was some error with un-frequencies calling the -helper function.

brunobraga23:03:59

hey guys, I am to print a persistentArrayMap like this: (doseq [[k v] j] (print k)) but I am gettin UnsupportedOperationException nth not supported on this type: PersistentArrayMap clojure.lang.RT.nthFrom (RT.java:983) which I guess means I cant iterate over this kind of data, does anyone know a workaround?

seancorfield23:03:35

@brnbraga95 call seq on the map.

seancorfield23:03:53

(although I would have expected doseq to do that for you)

seancorfield23:03:59

Yes, it does. Just confirmed that. @brnbraga95 can you share a bit more code? What you've written works if j is a hash map literal...

seancorfield23:03:22

boot.user=> (doseq [[k v] {:a 1 :b 2}] (println k))
:a
:b
nil
boot.user=> (type {:a 1 :b 2})
clojure.lang.PersistentArrayMap

brunobraga23:03:35

you are totally right. apparently what I got was something called lazySeq that is wrapping some persistentArrayMaps

brunobraga23:03:48

what I am trying to achieve is am array of jobs ids, types and urgences, which are the values of the persistentMaps, at this point I no longer care for key, which are always new_jobs

seancorfield23:03:20

Ah, you had a sequence of maps... So you want to produce a sequence of vectors? Like ([<uuid> bills-questions true] [...] [...]) ?

brunobraga23:03:50

Ideally I would like to have something like:

[
      "690de6bc-163c-4345-bf6f-25dd0c58e864": {
        "type": "bills-questions",
        "urgent": false
      }
]

seancorfield23:03:15

Since you're starting with a sequence and you want to produce a sequence of the same length, where each element is just a transformation of the original sequence, you want to call map and pass a transformation function:

(map some-function jobs)
where some-function takes a job hash map and produces a vector containing just the values of :id, :type, and :urgent...

seancorfield23:03:15

That's not a valid data structure -- did you want to produce a hash map, indexed by the job ID? (not a vector)

brunobraga23:03:12

yes, but I also want to be able to iterate over it, because I want to find workers for those jobs

brunobraga23:03:19

but I want the smallest payload

seancorfield23:03:28

If you want to go from a sequence of hash maps to a (new) hash map, then you want reduce.

brunobraga23:03:35

that is why I am trying to map over and make it a simpler data structure

brunobraga23:03:01

does not reduce "reduces" it to a single value?

brunobraga23:03:12

ooh I got you

seancorfield23:03:33

(reduce (fn [m job] (assoc m ...)) {} jobs)

seancorfield23:03:44

That will produce a hash map from the jobs. What you assoc into it will be the job ID (as the key) and then a hash map of just the keys you want (as the value).

seancorfield23:03:26

Is that enough to get you going in the right direction?

brunobraga23:03:45

yes it is, just to make sure. m is my current hash map (the accumalted), job is the current job I am iterating and {} is a starting hash map

brunobraga23:03:56

is that correct?