Fork me on GitHub
#beginners
<
2017-05-11
>
vitruvia02:05:24

can I iterate through strings or do I need to make them into sequences?

noisesmith02:05:12

any of clojure's iteration constructs will coerce the string to a sequence

noisesmith02:05:52

eg. (map int "this is a string") => (116 104 105 115 32 105 115 32 97 32 115 116 114 105 110 103)

john04:05:02

Unfortunately CLJS acts a little different with regard to strings. (char "t") => "t"

john04:05:56

and (map (memfn charCodeAt) "this is a string") => (116 104 105 115 32 105 115 32 97 32 115 116 114 105 110 103)

john04:05:57

there should really be a reader macro for memfn imo

crvst10:05:38

How to use async function like this: https://gist.github.com/scttnlsn/9744501?

crvst10:05:33

I need some fn to be debounced, but I have no idea even how to apply this stuff. I’ve imported all the dependencies from core.async, but the usage of the debounce fn from the gist is not that straightforward like _.debounce from lodash for instance.

crvst10:05:14

Here’s the listing:

(defn debounce [in ms]
  (let [out (chan)]
    (go-loop [last-val nil]
      (let [val (if (nil? last-val) (<! in) last-val)
            timer (timeout ms)
            [new-val ch] (alts! [in timer])]
        (condp = ch
          timer (do (>! out val) (recur nil))
          in (if new-val (recur new-val)))))
    out))

verma12:05:16

@crvst this seems to be using it for debouncing function calls instead of chans: https://gist.github.com/owenrh/8baeb98c5081ea648381

verma12:05:48

has some usage at the bottom as well

crvst12:05:55

Yep, thanks

vitruvia14:05:21

for writing docstrings in clojure do we use normal comments ; or should I use a different notation?

Sam H15:05:27

vitruvia: https://github.com/bbatsov/clojure-style-guide have a look at that page and search for docstring. Lots of useful info in general

vitruvia15:05:33

@U0DPX8ZQB what about the docstrings in these regex expressions? https://gist.github.com/clojens/7932406

Sam H16:05:20

Do you mean the :purpose sections?

Sam H16:05:30

Looks like that’s just a normal clojure map

vitruvia16:05:33

All of them, the purpose and the examples

vitruvia16:05:53

but its meant to work as a documentation, no?

Sam H16:05:16

No idea. Looks like a normal defining of a map

Sam H14:05:58

usually just quotes afaik

(defn method-name
  "doc string"
  [vars]
 (forms))

dpsutton15:05:38

i'm almost positive that using ; for comments will hide them from the tooling

Drew Verlee15:05:07

I’m giving a talk on Clojure today at my company. One topic i wanted to touch on was encapsulation. I was hoping to get some quick feedback on how to present the idea. 🙂 Its often argued that in OO classes “encapsulate”. I assumed the benfiet was to create more flexible programs by hiding low level details of some functionality (not data). This way those details could change without effecting callers. In clojure you can achieve a similar effect with cough closures. Is that all you would feel needs to be said on the subject? Or is there another way to think about it?

ghadi15:05:05

minimal need to encapsulate when data is immutable

ghadi15:05:50

this comes up on the mailing list quite a bit @drewverlee . Might want to search for a @tbaldridge rant

tbaldridge15:05:23

I don't remember too many epic rants on the subject...but I do have opinions 🙂

Drew Verlee15:05:46

Alex (from the twitter) seems to be suggesting because objects have a more tighter coupling to each other. Their more resilient to change. I think he is conflating data and functions together. I dont see why you would have more clojure functions acting on a given dataset in either language.

tbaldridge15:05:54

@drewverlee first thing that has to be done though is to define OOP. I go into it a bit here: https://www.youtube.com/watch?v=6tFSrnK7vmw

tbaldridge15:05:24

But the problem is this: you can make a mostly immutable OOP system (complete with inheritence).

tbaldridge15:05:48

You can make OOP systems without encapsulation, for example Python doesn't encapsulate except by convention.

tbaldridge15:05:20

And if people want abstract interfaces, there's things like protocols that allow for abstractions but without the drawbacks of traditional OOP systems.

mj_langford16:05:31

(defn -setup-tables
  "Makes sure all the database tables exist, does not perform updates though"
  [tables]
  (doseq [k (keys tables)
          :for [entry (get tables k)
                tn (:real-name entry)
                tcfg (:cfg entry)]]
    (far/ensure-table 
      far-opts
      tn 
      (:pk tcfg) 
      (:opts tcfg))))

mj_langford16:05:41

I'm constantly getting a NPE on that

mj_langford16:05:58

from the doseq line

mj_langford16:05:17

is there anything obviously wrong here? I am not a huge user of doseq/for

mj_langford16:05:57

this is what tables are

mj_langford16:05:03

(def -tables 
  (into {} 
     (map (fn [tbl] 
            {tbl {:real-name (-prefix tbl)
                  :cfg (get -configs-proto tbl)}})
          (keys -configs-proto))))

mj_langford16:05:20

And they do indeed exist:

mj_langford16:05:39

{:Eateries {:real-name testing-Eateries, :cfg {:pk [:id :s], :opts {:throughput {:read 2, :write 2}, :block? true}}}, :Users {:real-name testing-Users, :cfg {:pk [:id :s], :opts {:throughput {:read 2, :write 2}, :block? true}}}, :SeatingQueues {:real-name testing-SeatingQueues, :cfg {:pk [:eatery-id :s], :opts {:range-keydef [:user-id :s], :throughput {:read 2, :write 2}, :block? true}}}, :SeatingPools {:real-name testing-SeatingPools, :cfg {:pk [:eatery-id :s], :opts {:range-keydef [:user-id :s], :throughput {:read 2, :write 2}, :block? true}}}, :SeatingHistory {:real-name testing-SeatingHistory, :cfg {:pk [:history-id :s], :opts {:range-keydef [:user-id :s], :throughput {:read 2, :write 2}, :block? true}}}, :CreditTransactions {:real-name testing-CreditTransactions, :cfg {:pk [:transaction-id :s], :opts {:range-keydef [:eatery-id :s :user-id :s], :throughput {:read 2, :write 2}, :block? true}}}, :HoldsTransactions {:real-name testing-HoldsTransactions, :cfg {:pk [:user-id :n], :opts {:range-keydef [:eatery-id :s], :throughput {:read 2, :write 2}, :block? true}}}}

mj_langford16:05:23

Is doseq "collecting" up the NPEs as it's a macro or something like that? so I'm just looking on the wrong line for the NPE?

mj_langford16:05:08

Aaaaad, I found it...thank you for 🦆 ing today, :for was supposed to be :let

mj_langford16:05:54

I do find the NPE from a weird use of a macro frustrating. If there is any sort of OSS ticket like this I could apply myself towards to better clojure error messages on this front, I'd be game.

grounded_sage17:05:19

If I want to include a branch of a library instead of the master into my project how would I go about that?

Sam H17:05:33

grounded_sage: one way is to checkout the branch, build the jar and install it locally (with a different project version) and then just reference that in your project

grounded_sage17:05:45

Cheers. I had a feeling this would be the way to do it. Was hoping to see if there was other ways.

mss17:05:24

how do people structure clojure applications which have to make 1000s of blocking io calls per second? utilize a variable thread pool? use continuation passing style? some other concurrency model? newish to the jvm so my understanding of concurrency constructs might not be great

noisesmith17:05:55

why do the io calls need to block?

mss17:05:17

well, maybe they don’t. to be precise, I’d like to make 1000s of db calls via jdbc per sec. I don’t know if there’s a non blocking jdbc model

mss17:05:47

my impression was that everything was blocking in that model

noisesmith17:05:47

once you are talking about that kind of input, it’s much more useful to talk about the specific db

mss17:05:53

yeah just generic mysql 5.6

mss17:05:01

using mysql jdbc driver

mss17:05:02

my impression is that any calls via that driver block

noisesmith17:05:25

yes, that’s true

noisesmith17:05:35

there’s an async psql driver iirc

noisesmith17:05:21

anyway, I think a reasonable model if you want to maximize throughput is to have a connection pool, and a worker pool, and a queue that gets jobs plus (callbacks or channels or promises or whatever) to deliver the data to when fetched

noisesmith17:05:39

c3p0 is a connection pool for jdbc that’s easy to use from clojure

mss17:05:53

definitely. using hikari rn but same idea

noisesmith17:05:01

oh, and the queue I mention above could easily be a channel (that’s just an implementation detail)

vitruvia17:05:06

can anyone tell me why the regex "[^A-z\s0-9]" doesn't filter out the ^ symbol? for example if I use it on "test^" I want to get "test" but I just get the same string

mss17:05:06

ya that makes sense

noisesmith17:05:26

@vitruvia [^x] negates the matching of x

noisesmith17:05:39

if you want to match x and ^, you need [x^]

echristopherson17:05:38

I think he's trying to filter out characters that don't match.

noisesmith17:05:01

then you want [^^x] I think

noisesmith17:05:43

=> (re-seq #"[^^x]+" "fooxbar^baz")
("foo" "bar" "baz")

noisesmith17:05:16

right, and if you also want to exclude the symbol itself, you need to provide it twice, once to negate, another time to specify itself

vitruvia17:05:17

but I'm not trying to exclude the symbols inside [], I'm trying to exclude anything that is not in [^A-z\s0-9]

vitruvia17:05:04

and it works for everything but the ^

noisesmith17:05:30

the ^ means “match the opposite of everytihng inside this []”

noisesmith17:05:49

it is a meta-character in that context, a syntax of regex

noisesmith17:05:53

it doesn’t stand for itself

vitruvia17:05:54

yes but the filter says = nil, so I want stuff that don't match it

noisesmith17:05:13

then you need it to be matched for the negation to work, and currently it is not matched

noisesmith17:05:44

also I find the double-negation odd, you can remove the negation from the character class and remove the = nil step and get the same logical result

noisesmith17:05:50

I think (str/lower-case (apply str (re-seq #"[A-z\s0-9]+" %))) should get the same result, much more efficiently

vitruvia17:05:15

thanks. Curiously, doing the double negation doesn't change the result for me

noisesmith17:05:55

change A-z to A-Za-z

noisesmith17:05:51

^ is inbetween Z and a

noisesmith17:05:41

peregrine.circle=> (str/lower-case (apply str (re-seq #"[A-z\s0-9]+" "hello, ^world")))
"hello ^world"
peregrine.circle=> (str/lower-case (apply str (re-seq #"[A-Za-z\s0-9]+" "hello, ^world")))
"hello world"

vitruvia17:05:48

never would have imagined

vitruvia17:05:53

thanks a lot

vitruvia17:05:22

I thought alpha characters didn't have anything between them in unicode

noisesmith17:05:58

=> (char (inc (int \Z)))
\[

vitruvia18:05:24

by the way @noisesmith do you think this is a good course? http://mooc.fi/courses/2014/clojure/ I hear good things about their java courses but I don't know if this one is good too

noisesmith18:05:37

I don’t know that course at all, sorry - I can recommend http://purelyfunctional.tv though

vitruvia18:05:00

alright. I'll check that one, too. Thanks

noisesmith18:05:23

I think they have some free videos still, and the guy who makes them really knows the material well

rgdelato18:05:01

Are there any good resources for knowing what syntax-quote actually is doing? I thought it was the same as a normal quote (except it allows unquote), but when I do (backtick + single quote):

`'(~a 2 3) ;=> (quote (1 2 3))
...I get a different result than (backtick + backtick):
``(~a 2 3) ;=>
;; (clojure.core/seq 
;; (clojure.core/concat 
;;  (clojure.core/list user/a) 
;;  (clojure.core/list 2) 
;;  (clojure.core/list 3))) 

noisesmith18:05:01

@rgdelato ` breaks down and reconstructs your form, not only does it allow unquote and unquote splicing, it also namespace qualifies any symbols not bound locally

noisesmith18:05:38

the result of the concat will look like (user/a 2 3) and hopefully a is 1 and you get your expected result

noisesmith18:05:42

of course this wouldn’t be correct coming from a macro, as it emits code that tries to call a as a function (and you report that a is a number)

noisesmith18:05:40

@rgdelato regarding your actual question, I think this is the best explanation of syntax-quote https://clojure.org/reference/reader#syntax-quote

noisesmith18:05:18

note in particular this paragraph

For Lists/Vectors/Sets/Maps, syntax-quote establishes a template of the corresponding data structure. Within the template, unqualified forms behave as if recursively syntax-quoted, but forms can be exempted from such recursive quoting by qualifying them with unquote or unquote-splicing, in which case they will be treated as expressions and be replaced in the template by their value, or sequence of values, respectively.

noisesmith18:05:52

the whole seq / concat / list transformation nest is part of the templating

rgdelato18:05:58

okay, I'm kind of understanding it. it'll certainly take some time to sink in, but this is a good starting point. thank you for the explanation 😄

deg18:05:42

Is there a built-in function like

(defn get-at [coll id-key id key]
  (-> #(= (id-key %) id)
      (filter coll)
      first
      key))
e.g., (get-at [{:id 1 :label "one"} {:id 2 :label "two"} {:id 3 :label "three"}] :id 2 :label) ==> "two" I find myself using this pattern a lot recently.

noisesmith18:05:51

sounds like something spectre would do https://github.com/nathanmarz/specter

deg18:05:32

Hmm, thanks. I read the specter readme a while back and filed it away as something to look at later.

Alex Miller (Clojure team)19:05:32

actually, not reading closely enough - I guess you’re one step beyond that

echristopherson19:05:13

It's the heavy heavy monster sound!

deg21:05:25

@alexmiller Yup, not the same, but quite useful. Upvoted.

Drew Verlee21:05:53

I just gave a short clojure talk to my coampny, I guess every lisp talk needs a 10 minutes discussion about if parens are readable.

Alex Miller (Clojure team)21:05:12

it’s not that lisp/clojure have more parens. it’s that they have less of everything else.

ghadi22:05:37

i always use a line about "Musicians don't see barlines"

Drew Verlee22:05:19

@alexmiller I’m sure its an argument your tired of hearing. In the conversation i earnestly asked them what measure they used for readability. I think most were just uncomfterable with the idea that in 5 minutes they knew the entire language syntax. The best attempt i have seen to address readability was at my first StrangLoop: https://www.youtube.com/watch?v=uEFrE6cgVNY

Drew Verlee22:05:23

Someone also said it was harder because “we talk in statements so our PL should have them” to which i had no rebuttal because i was having trouble understanding it.

Alex Miller (Clojure team)22:05:23

@ghadi that does not seem accurate :)

Alex Miller (Clojure team)22:05:14

bar codes seem pretty fundamental to breaking music into rhythmic units

Alex Miller (Clojure team)22:05:20

like the parens in lisp

ghadi22:05:42

I don't focus on the barline, I focus on the content

ghadi22:05:20

but yeah they're fundamental to the structure, they're just not the important bits

ghadi22:05:32

beginner's bias

ghadi22:05:59

I'd love to hear other techniques for defusing the syntax objection

mobileink17:05:40

ghadi: "In Clojure, parens are optimized for parafoveal vision, so it's scientifically easier to read." That should shut 'em up for a while.

ghadi22:05:07

it is annoyingly persistent

Drew Verlee22:05:17

@ghadi Most people i meet are using language because someone else told them to. So one way is to just be in charge :man_in_business_suit_levitating:

noisesmith22:05:18

a lisp has the same parens you’d see with function calls most other places, they are just moved one full word to the left f() -> (f)

ghadi22:05:20

I guess we could just not care if people said "eww, gross!" except when people say "eww, gross!" it means learning is turned off

john22:05:40

“we talk in statements so our PL should have them” except, they aren't really english statements, are they? So you have to learn an entirely new language. So why make it more complex than it needs to be?

john22:05:04

And when you do, you just end up wrestling with the syntax in order to produce your desired AST. So why not just program the AST directly?

mobileink17:05:40

ghadi: "In Clojure, parens are optimized for parafoveal vision, so it's scientifically easier to read." That should shut 'em up for a while.