Fork me on GitHub
#clojure
<
2015-09-11
>
jmglov00:09:17

@denik: Were you thinking of Slingshot?

nberger00:09:56

(a gazillion messages before) he said it's not slingshot

unbalancedparentheses00:09:32

hi everybody! i wanted to know if I forgot any important link in my post for clojure starters (https://medium.com/this-is-not-a-monad-tutorial/how-to-earn-your-clojure-white-belt-7e7db68a71e5). let me know if I should add anything please 😄

wqhhust01:09:45

why the memory keep going up when run this query? The table of test is huge. Anyway to let clojure not consume so much memory? I am testing the network performance of db, so didn't count it inside db. (count (j/query db ["select * from test"]))

wqhhust02:09:11

@beppu , thanks, good information

amacdougall02:09:13

@nberger: You'll be happy to know that I just added ring-logger-timbre to my middleware stack, and it was painless and effective. It's successfully telling me exactly what the incoming requests are.

amacdougall02:09:05

Curiously, this test code:

(let [credentials (select-keys user-values #{:username :password})
          request (-> (request :post "/api/login")
                    (content-type "application/json")
                    (body credentials))
          response (app request)]
      (is (= 200 (:status response))))
...is generating a request which, according to ring-logger, has :content-type "application/x-www-form-urlencoded". I'm investigating further. But that may explain why the compojure.api code hasn't been handling it correctly. I know that Transit is recommended for Clojure + ClojureScript apps, but at this point I feel like I need to see this JSON battle to its end for my own education.

amacdougall02:09:19

(Okay, I just realized that I was shadowing request (from ring.mock.request) with request (the let binding), but that's not actually a bug here -- just ugly and confusing.)

amacdougall02:09:29

I believe I might have found it! When using ring.mock.request in this way, I need to explicitly encode the JSON body as a string, because ring.mock.request/body is a multimethod which handles a map argument by changing the content type to application/x-www-form-urlencoded. Whew!

amacdougall02:09:01

I would argue that if the content-type is already application/json, ring.mock.request should assume that the body map is a JSON hash, but that's another story.

nberger02:09:28

Indeed, I'm happy ring-logger-timbre is helping. And I agree, would be great if ring.mock.request was smarter there...

amacdougall02:09:33

And that let me finally drill down to the last bug in my code, which was that I was invoking the raw user creation function generated by YeSQL, not my model-level user-creation function -- so the user I was creating in the test database had a plaintext password instead of a hashed one, which (for whatever reason) caused buddy-hashers/check to bust a gut.

amacdougall02:09:31

I'll make a note to offer a PR about the ring.mock.request thing. JSON requests built from plain maps are pretty common.

amacdougall02:09:59

Thanks for all your help! I'm sure I'll be back with more problems.

nberger02:09:04

It seems https://github.com/xeqi/peridot already handles this a bit better. In the README I'm reading the following: > By default, when POSTing data, params will be encoded as application/x-www-form-urlencoded. If you want to use an alternative encoding, you can pass :content-type as an option, and use :body instead of :params

amacdougall03:09:23

Ah, I've seen people mention it. Maybe I'll try that out instead.

amacdougall03:09:51

That said, it can't hurt to file a PR on ring.mock.request anyway if it might help someone!

mr-spock10:09:09

Hi. Does anyone can help with something that looks simple but I’m stuck

mr-spock10:09:20

I have clojure.lang.LazySeq as a result of PGSQL query which contains ~ 35k rows. I’m trying to build atom based in-memory store since those data rarely change with simple

mr-spock10:09:19

(defn update-cache [cache mac serial] (swap! cache conj {mac serial}))

mr-spock10:09:23

(defn make-cache [cache records] "Fill in-memory atom cache with data from giver record" (let [recs (vec records)] (dosync (map #(update-cache cache (:mac %) (:serial %)) recs) )))

mr-spock10:09:35

(def cache (atom {}))

mr-spock10:09:02

And when I call (make-cache cache 35k-records) I’m getting out of memory …:(

magnars10:09:55

first, calling vec on records makes it no longer lazy

mr-spock10:09:00

That is my point

mr-spock10:09:05

since otherwise map will not finish

magnars10:09:07

and you're holding onto the head

magnars10:09:40

map is used for returning a new seq

magnars10:09:50

you want to do side-effects, then use doseq

mr-spock10:09:50

I want to build my memor-based-cache for further queries

magnars10:09:53

(doseq [rec records] (update-cache cache (:mac rec) (:serial rec)))

mr-spock10:09:01

let me check

mr-spock10:09:44

Yes - you are of course right simple_smile

mr-spock10:09:45

cl-repl.core=> (count @cache) 0 cl-repl.core=> (count r) 32116 cl-repl.core=> (make-cache cache r) nil cl-repl.core=> (count @cache) 32116 cl-repl.core=>

mr-spock10:09:11

Now it works like a charm.

mr-spock10:09:25

cl-repl.core=> (get @cache "647c344792ee" "UNKN") "uaap41940384"

amithgeorge12:09:02

In the book Clojure Applied, while talking about core.async channels and pipelines, the author presents the following snippet - http://media.pragprog.com/titles/vmclojeco/code/cljapplied/src/ch5/pipeline.clj

amithgeorge12:09:41

An intermediate channel is used to separate the filtering of interesting words and sentiment analysis of those words. The idea being we could have a separate state log-words which operates on the intermediate channel in parallel.

amithgeorge12:09:57

I can't figure out how both sentiment-analysis and logging stages will get the same word? Once one of those stages takes a word off the intermediate channel, isnt it lost for forever? How does another consumer see that word?

amithgeorge12:09:28

;---
; Excerpted from "Clojure Applied",
; published by The Pragmatic Bookshelf.
; Copyrights apply to this code. It may not be used to create training material, 
; courses, books, articles, and the like. Contact us if you are in doubt.
; We make no guarantees that this code is fit for any purpose. 
; Visit  for more book information.
;---
(ns ch5.pipeline
  (:require [clojure.core.async :as async]))

;
;; parse message into set of words
(def parse-words (map #(set (clojure.string/split % #"\s"))))

;; filter messages that contain a word of interest
(def interesting (filter #(contains? % "Clojure")))

;; detect sentiment based on different word lists
(defn match [search-words message-words]
  (count (clojure.set/intersection search-words message-words)))
(def happy (partial match #{"happy" "awesome" "rocks" "amazing"}))
(def sad (partial match #{"sad" "bug" "crash"}))
(def score (map #(hash-map :words %1
                           :happy (happy %1)
                           :sad (sad %1))))
;

;
(defn sentiment-stage
  [in out]
  (let [xf (comp parse-words interesting score)]
    (async/pipeline 4 out xf in)))
;

;
(defn interesting-stage
  [in intermediate]
  (let [xf (comp parse-words interesting)]
    (async/pipeline 4 intermediate xf in)))

(defn score-stage
  [intermediate out]
  (async/pipeline 1 out score intermediate))

(defn assemble-stages
  [in out]
  (let [intermediate (async/chan 100)]
    (interesting-stage in intermediate)
    (score-stage intermediate out)))
;

Alex Miller (Clojure team)13:09:01

@amithgeorge: that's not actually done here but you would need to use a core.async mult that fans out to multiple output channels -this is covered more in ch 6 and there is an example there connect-and-tap. That could be applied to the intermediate input channel in the example above.

csmith13:09:04

Hi @unbalancedparentheses . I thought it some nice highlights. Thanks

mr-spock14:09:30

Guys - how to access atom that is in another namespace ? Lets say I have (require `[my-project.db :as db] and within db is (def cache (atom {}))

mr-spock14:09:39

db/@cache doesn’t work

mr-spock14:09:44

@db/cache - the same

gtrak14:09:10

@db/cache should work, maybe you haven't recompiled properly

gtrak14:09:14

also, it's an antipattern

mr-spock14:09:39

something wrong with my compliation then

gtrak14:09:48

transducers gotcha: (comp .. (distinct)) not (comp ... distinct) /facepalm

meow14:09:47

@gtrak: Yeah, I think cat is the only transducer in core - everything else is some function that returns a transducer.

meow14:09:05

Speaking of transducers, has anyone had a need to use a custom reducing function instead of just conj?

meow14:09:20

I've done some work with interesting transducer stacks, including stateful transducers, but I still haven't seen a need for anything unusual for the reducing function.

Alex Miller (Clojure team)14:09:23

@meow: re cat - yes, that's the only function that is a transducer rather than a creator of a transducer

Alex Miller (Clojure team)14:09:00

building an output collection is certainly one of the most common reducing functions (which really I'd recommend into for that use case)

Alex Miller (Clojure team)14:09:27

but any time you are "summarizing" a collection down to a value you will need something different

Alex Miller (Clojure team)14:09:46

for example, + would be a "summing" reducing function

meow15:09:26

@alexmiller: So the code I've been working on is basically building output collections - so you recommend into - any particular reason?

Alex Miller (Clojure team)15:09:43

and it's optimized for transients

meow15:09:52

ok, makes sense

Alex Miller (Clojure team)15:09:30

will be faster than the naive version of (transduce xf conj input)

Alex Miller (Clojure team)15:09:57

plus you can easily change to a different output collection type

amithgeorge15:09:01

@alexmiller: thanks. had read only till the end of chap 5, for today simple_smile

meow15:09:35

@alexmiller: looks like I need to revise my code, once again... will it never end... 😉

meow15:09:15

I've been using tranduce where I should use into

Alex Miller (Clojure team)15:09:17

(it will never end btw :)

meow15:09:35

neverending is a good thing

meow15:09:49

so I've been writing variations on this theme:

([get-xf get-rf]
   (letfn [(process [w]
                    (lazy-seq
                      (when (seq w)
                        (let [word (transduce (get-xf) (get-rf) w)]
                          (cons word (process word))))))]
     (process jumpstart))))

meow15:09:46

get-xf has been a very useful way to plug in various transducer stacks, but I haven't had a use for get-rf beyond the default that I supply.

meow15:09:55

So I've been thinking about taking it out.

meow15:09:18

If I switch from transduce to into I'm wondering if I need any flexibility here or if (into [] (get-xf) w) is all I will ever need?

Alex Miller (Clojure team)15:09:57

if you're always collecting then taking the initial output collection (here []) would give you an intermediate level of flexibility

Alex Miller (Clojure team)15:09:20

although maybe you don't even need that

meow15:09:49

this process is recursive and axiomatic, meaning there is an intial collection and it gets fed back into the process

meow15:09:27

I'm not sure I can think of a need for a collection other than vector

meow15:09:04

but that's why I'm asking... 😉

meow15:09:16

and I just learned about transients - cool http://clojure.org/transients

meow15:09:58

so I can definitely see that if into is making use of transients then it should definitely be better than transduce in my use-case, which because of the recursive rewriting can easily produce collections with millions of items after just a few iterations.

meow15:09:13

@alexmiller: and now I see what you mean by looking at the source for into:

([to xform from]
     (if (instance? clojure.lang.IEditableCollection to)
       (with-meta (persistent! (transduce xform conj! (transient to) from)) (meta to))
       (transduce xform conj to from)))))

meow15:09:52

so vector, hash-map, and hash-set

meow15:09:10

hmm, I'm a bit confused by this:

(type {})
=> clojure.lang.PersistentArrayMap
(type (hash-map))
=> clojure.lang.PersistentArrayMap
(type (array-map))
=> clojure.lang.PersistentArrayMap

gtrak16:09:06

actually I can't see where that happens either simple_smile

csmith17:09:04

@meow: My understanding is that the underlying type and implementation of hash map is to use PersistentArrayMap for sufficiently small maps, and convert to PersistentHashMap after a sufficient size is reached. Something like 8 or so pairs

csmith17:09:21

E.g:

user=> (type {})
#<java.lang.Class@6611df92 class clojure.lang.PersistentArrayMap>
user=> (type {:a 3 :b 3 :c 3 :d 3 :e 4 :f 3 :g 3 :h 3 :i 3 :j 3})
#<java.lang.Class@21507a04 class clojure.lang.PersistentHashMap>

gtrak17:09:36

then somewhere we should see 'new PersistentArrayMap', but cursory investigation shows that's not called anywhere from PHM.java

seancorfield17:09:33

http://clojars.org seems to be struggling today… lots of 500 server error responses or very very slow to load / respond…

curtosis18:09:24

anyone successfully using a local repository with a "file:" url for local jars? I had one working at one point and for some reason it just stopped.

curtosis18:09:00

(probably at least slightly triggered by clojars throwing 500s....?)

curtosis18:09:39

the symptom I'm getting is IllegalArgumentException: number of transferred bytes cannot be negative from aether, which is unhelpful.

seancorfield18:09:28

I’m not sure why Leiningen would even both to contact http://clojars.org when we have the JAR in the local Maven cache 😞

Alex Miller (Clojure team)18:09:02

if you have snapshots, it will check for newer ones in remote repos

Alex Miller (Clojure team)18:09:06

for non-snapshots, not sure why

Alex Miller (Clojure team)18:09:46

that should be local only I think

curtosis18:09:57

"The repository system is offline but the artifact [my-artifact] is not available in the local repository."

curtosis18:09:29

which actually seems extra weird, because that shouldn't be the case.

curtosis18:09:52

by which I mean, there is the local repository, which is one thing, but I also have a "local" (i.e., with a "file:" url) repo in my :repositories for the project.

Alex Miller (Clojure team)18:09:02

well the latter is probably treated as a "remote" repo regardless

Alex Miller (Clojure team)18:09:42

it's possible that you got a bad jar downloaded in your local cache - I have seen maven download an http error form and save it as a jar before

Alex Miller (Clojure team)18:09:20

you might want to do some minimal investigation whether the jars in the .m2 are valid

curtosis18:09:14

spot checks of jars indicate cached .m2 versions are identical to my "local" repo versions

curtosis18:09:00

but I'm not entirely sure why it's not looking in the "local" repo and only clojars. Or, for that matter, even if it is looking at the "local" repo.

Alex Miller (Clojure team)18:09:49

yeah, not sure I can help more at this point

Alex Miller (Clojure team)18:09:05

sometimes I have found it useful to do "lein pom" then use Maven to see its errors

Alex Miller (Clojure team)18:09:18

"mvn dependency:tree" should be sufficient

Alex Miller (Clojure team)18:09:31

and you can get more error reporting with "mvn -X dependency:tree"

curtosis18:09:46

I'll give that a shot

curtosis18:09:19

two warnings; neither of my libraries have associated poms

Alex Miller (Clojure team)18:09:25

pkobrien and gtrak - from your earlier question, (hashmap) will return literal {}, which (since 1.7 I think) will be a PAM, not a PHM. That is probably more accident than intention.

curtosis18:09:05

but mvn seems to be able to find the repo just fine

Alex Miller (Clojure team)18:09:35

pkobrien: gtrak: actually that didn't change in 1.7, would have been same prior

curtosis18:09:04

hmmmm... this could be a bug in aether. lein is using sonatype-aether, which is officially deprecated.

curtosis19:09:33

and there's a known bug in sonatype-aether that would cause exactly these symptoms on an existence check.

curtosis19:09:33

(short version: total transferred bytes is initialized to -1; existence check branch doesn't/didn't reset that to zero)

curtosis19:09:25

anyway... I think that's likely the culprit, but the linkage between lein and aether is far too obscure for me to know where to start to address it.

Alex Miller (Clojure team)19:09:41

I think lein uses pomegranate which uses the aether stuff

Alex Miller (Clojure team)19:09:51

so pomegranate is likely the place

curtosis19:09:27

given that sonatype-aether was deprecated 4 years ago, that sems like a problem. 😉

curtosis19:09:12

though to be fair, pomegranate appears more or less "done" and not actively developed.

timvisher19:09:19

i was considering using automat to describe the state transitions that can happen to one of our domain entities here, but i’m struggling to see how you can ‘drop into the middle’ of the FSM.

curtosis19:09:29

eclipse-aether was supposedly massively rewritten, but I don't know if it's api-compatible enough to just swap into pomegranate

timvisher19:09:30

i.e. if i have a state machine that goes something like [1 (a/* [2 3]) 4]

timvisher19:09:13

i’d like to be able to use it such that (f :current-state-of-the-thing :proposed-state-of-the-thing) -> truthy if it could advance the FSM

timvisher19:09:46

as near as i can tell, the way you would go about doing that is by constructing an automat state map and passing that in to advance

timvisher19:09:58

but it uses ‘internal’ state indexes rather than the edge names

timvisher19:09:06

(i’m probably not even using the right terminology)

timvisher19:09:12

any thoughts?

timvisher19:09:54

i suppose i could cache off somehow the advances of any given domain entity through the fsm but that seems like much more trouble than its worth given that i can express this logic pretty simply otherwise

curtosis19:09:38

aha... already an open PR on pomegranate. https://github.com/cemerick/pomegranate/pull/70

curtosis19:09:35

with workaround!

beppu19:09:04

@timvisher: If your finite state machine is implemented using state transition tables, it's very easy to make a function that does: (f :current-state-of-the-thing :proposed-state-of-the-thing) -> truthy if it could advance the FSM

bsima19:09:15

I think I just broke http://clojars.org - I was just trying to update by PGP key, and now the entire site errors out 😞

beppu19:09:30

(def fsm {:A {:a :B :b :C} :B {:a :A :b :C} :C {:a :C :b :C}})
(defn new-state [machine state inputs] (reduce (fn [s i] (-> machine s i)) state inputs))
(defn possible? [fsm a b] (-> fsm a vals set (contains? b)))

beppu19:09:05

@timvisher: The possible?function is what tells you if the fsm allows transitions from state a to state b.

beppu19:09:53

Examples:

(new-state fsm :A [:a])       ; => :B
(new-state fsm :A [:a :a])    ; => :A
(new-state fsm :A [:a :a :b]) ; => :C
(possible? fsm :A :A)         ; => false, it is not possible to move from :A to :A
(possible? fsm :A :B)         ; => true
(possible? fsm :A :C)         ; => true

Pablo Fernandez19:09:28

Does anybody know if it’s possible to specify individual files with cljsbuild to compile, instead of all files in a directory?

beppu19:09:49

You should ask in #C03S1L9DN.

Pablo Fernandez20:09:57

beppu: I already did that, but nobody knew over there. I thought someone here might know.

beppu20:09:04

oh sorry.

beppu20:09:42

^-- he's the guy that's keeping http://clojars.org up and running these days.

beppu20:09:16

At the last Clojure/West, he was looking for people to help him with existing issues. Everything marked ready is stuff that he'd like help with: https://github.com/ato/clojars-web/issues?utf8=%E2%9C%93&amp;q=is%3Aissue+is%3Aopen+label%3Aready

bsima20:09:46

oh thanks

beppu20:09:03

I put out the bat signal. Hopefully he responds. 😛

bsima20:09:25

I saw on reddit that clojars needs help, but I've only been a consumer of clojure libraries up until now

beppu20:09:28

It's not a bad way for an intermediate-to-advanced programmer who is new to Clojure to get their feet wet with programming in Clojure.

beppu20:09:05

It's a nice medium-sized project. It's not too complex. A little crufty here and there, but not terrible.

bsima20:09:22

awesome, looks like my weekend just filled up simple_smile

beppu20:09:02

I fixed one issue for implementing pagination on the search page. I told him I'd send him a pull request after Clojure/West and I did a few days after, but then I got busy at work and forgot about following up on it. Some months after Clojure/West, I finally did get around to finishing that feature after he pinged me via email.

beppu20:09:09

I'm sure he'll be happy to get help. It's been a thankless job.

cfleming20:09:09

@bsima: I can confirm that @tcrawley would love some help, and that there’s plenty to do. It’s also a great way to help the community out, since it’s such a key piece of infrastructure.

bsima20:09:05

okay, I have clojars-web running locally, so the hard part is over and fun part of fixing bugs begins simple_smile

timvisher21:09:22

@beppu: true. i was hoping that automat would implement that sort of behavior for me

tcrawley22:09:19

If you were having trouble with clojars, it should be fixed now. the server ran out of disk space

beppu22:09:48

What did you delete to free up space?

tcrawley22:09:01

a 9.7gb error.log from nginx

tcrawley22:09:16

space is getting tight on that box, I need to move it to a bigger one

tcrawley22:09:35

sorry for the delay, I was far from a computer for a few hours :)

beppu22:09:43

Thank you for keeping things running.

beppu22:09:25

@timvisher: I looked at automat just now, and I was hoping I could see the inside of a compiled fsm, but it's a mysteriously opaque value.