Fork me on GitHub
#clojure
<
2016-01-03
>
underplank03:01:01

Anybody else having issues getting to clojars?

underplank03:01:24

dig seems to be resolving, so it doesnt seem to be dns issues.

adammiller03:01:37

linode still under ddos attack in atlanta which is where it’s hosted

underplank03:01:21

ahh righto. are there any mirrors around that we can fall back to?

underplank03:01:39

thanks @adammiller ! I thought there might be one. Lucky we got that funding for clojars not very long ago right??

adammiller03:01:00

yep, hopefully everyone keeps funding every month to keep it going and help build out some redundancy

akhudek06:01:34

and lein now goes back to trying to contact clojars despite having a mirror set

akhudek06:01:00

even stranger is that LEIN_OFFLINE claims a whole bunch of plugins are missing, but they are clearly in ~/.m2

akhudek06:01:19

it's being very inconsistent

kardan06:01:10

New mirror worked for me, thanks!

jimmy06:01:16

hi guys, is there anyway to enable debug log in aleph to log out some information about the request so it would be easier to work in dev env ?

ratnakar07:01:57

I am new to clojure, and doing the online mooc on clojure, I am trying to do an exercise, and I am trying to check if an argument is list, and return the length of the vector

ratnakar07:01:04

(defn generic-doublificate [x] (cond ((list? x) "A") (number? x (* x 2)) (empty? x nil) :else true ) )

ratnakar07:01:14

(defn generic-doublificate [x] (cond ((list? x) "A") (number? x (* x 2)) (empty? x nil) :else true ) )

ratnakar07:01:56

when I run the above I get a error saying cond requires an even number of forms,

ratnakar07:01:40

I am able to check whether list on the repl, but when I add to condn, it gives error. Can somebody help me?

flyboarder07:01:07

@ratnakar: you have an odd number forms in that example, in your cond every two forms are a pair

ratnakar07:01:08

@flyboarder: Thank you, Ahh, I see you mean in my eg list? and number? are 1 pair, and empty? + something else should be another pair?

jimmy08:01:23

hi guys, I'm a bit stuck in how to print message in ring middleware ?

jimmy08:01:38

I've tried both prn and (.println System/out msg) but it doesn't seem to work 😞

flyboarder08:01:45

@nxqd: does (println “Hello World!”) not work?

jimmy09:01:27

nah it doesn't work

jimmy09:01:06

to be more clarify, the code is like this :

(defn wrap-connection [handler conn]
  (fn [req]
    (println "test") ;; this does not work
    (handler (assoc req :datomic conn))))

(defn counter-om-handler [conn]
  (-> (wrap-connection handler conn)))

(defn counter-om-handler-dev [conn]
  (fn [req]
   ;; this prn works 
    (prn (clojure.pprint/pprint (-> req :body bs/to-string)))
    (counter-om-handler conn) req))

triss12:01:24

hey all. what's the simplest way to check if a value is an atom across clj and cljs?

pesterhazy12:01:50

@triss, cljs: (instance? Atom x) clj: (instance? clojure.lang.Atom x)

pesterhazy13:01:56

I've finished the draft of a guide to Threading Macros, for possible inclusion on : https://github.com/pesterhazy/clojure-site/blob/threading-macros/content/reference/threading_macros.adoc -- I'd be happy to get feedback of all types!

Alex Miller (Clojure team)14:01:24

If you file a PR, I will be happy to review in depth

pesterhazy14:01:49

@alexmiller: ok. I'll do another round of language fixes and open a PR then

andrea.crotti14:01:51

mm I just realised that these two are equivalent

andrea.crotti14:01:50

why leaving both ways, in the "Clojure Applied" book both styles are used in the same page even

pesterhazy14:01:37

@andrea.crotti: only the first one is valid, I think

andrea.crotti14:01:04

they both work in the same awy

andrea.crotti14:01:06

(with-doc2 232) 232 clojure-applied.store> (with-docstring 232) 232

andrea.crotti14:01:46

ah wait but with this (defn with-doc2 [x] "hello" x)

solicode14:01:46

They’re not equivalent though. The second doesn’t add any metadata on the function.

andrea.crotti14:01:52

doesn't go in the docs

andrea.crotti14:01:57

ok just a mistake in the book then

pesterhazy14:01:04

boot.user=> (defn a [] "aaa" nil)
#'boot.user/a
boot.user=> (doc a)
-------------------------
boot.user/a
([])
  nil
nil
boot.user=> (defn b "bbb" [] nil)
#'boot.user/b
boot.user=> (doc b)
-------------------------
boot.user/b
([])
  bbb
nil 
`

solicode14:01:07

The string is just being thrown away

pesterhazy14:01:55

the second is equivalent to (defn with-doc2 [x] (do "hello" x))

andrea.crotti14:01:18

yeah I noticed thanks, I'll raise a bug report for the book\

pesterhazy14:01:43

the reason that the docstring goes first is that there can be only one docstring but multiple arities and thus multiple arglists

Alex Miller (Clojure team)14:01:05

I think there is already an errata for this

pesterhazy14:01:41

it's not particularly intuitive though: maybe defn should have an assert that the first expr (of several) in the defn is not a string?

Alex Miller (Clojure team)14:01:53

If you don't see it, feel free to log, thx!

Alex Miller (Clojure team)14:01:59

I'm not sure when they are going to let us do an ebook update

amacdougall17:01:02

Your cautionary tale for the day—first I put a (map <side effect function> lazy-input) and expected to get the full result list... then when I finally put a doall in front of it, I hit useless SQLExceptions about how my transaction had been aborted. After a while, I realized that I was handling SQLExceptions in one of my model creation functions by returning nil. I thought, at the time, "oh, it's okay to return nil if a table-level constraint fails... Clojure is good at handling nils!" But obviously, in the context of a larger transaction, there's a Java/Postgres world down there that doesn't follow the same rules.

amacdougall17:01:31

The moral of the story: if you think you're converting errors from outside idioms to Clojure idioms, make sure you really, really are.

amacdougall17:01:15

The moral of the moral: If you wouldn't swallow exceptions in Java, don't swallow them in Clojure.

shanekilkelly17:01:44

All good points @amacdougall . I’m coming to the conclusion that jdbc/sql libraries are one of those places where the Java under-layer pokes through in painful ways.

shanekilkelly17:01:05

probably un-avoidable, given we’re piggybacking on jdbc

nberger18:01:09

@nxqd: looking to your pasted code, you are missing a pair of parens in the handler, so the result of (wrap-connection conn) is never called. It should be:

(defn counter-om-handler-dev [conn]
  (fn [req]
   ;; this prn works 
    (prn (clojure.pprint/pprint (-> req :body bs/to-string)))
    ((counter-om-handler conn) req)))

nberger18:01:19

added wrapping parens in ((counter-om-handler conn) req)

amacdougall18:01:25

By the way, anyone have a suggestion for test data generation? This mess all started when I tried to use a Prismatic Schema generator to whip out 100 randomly generated users based on a schema, but it was too easy for it to generate non-unique values for unique fields like username/email.

amacdougall18:01:21

I can definitely screw around with it until it works, but I also suspect that it's meant for straight up function-based chaos-intensive property testing more than for simulating realistic user data.

amacdougall18:01:41

A library that forces me to handle "\"^-.$$" as a legit username is valuable in one way; a library that can generate complex nested test data is valuable in another. (Gonna try out jFairy maybe? I mean, it's Java, so of course there are like a hundred possibilities...) (Also, should "\"^-.$$" be a legit username?)

akiva18:01:04

@amacdougall, have you looked into test.chuck and test.check?

akiva18:01:16

I’m actually messing around with this very issue today.

amacdougall18:01:57

Hm, test.chuck could be handy!

amacdougall18:01:48

Ultimately it's not going to be that big of a deal to write a function which generates n unique values given an infinite sequence.

davidg18:01:49

So swallowing database errors would be normal and effective in an all-Clojure stack, but fails because Java doesn't play ball? Can someone explain?

andy.fingerhut18:01:51

@pesterhazy: The Eastwood Clojure lint tool will warn about misplaced doc strings in your code: https://github.com/jonase/eastwood

amacdougall19:01:29

@davidg: It's probably a terrible idea there as well! But in Clojure, a lot of functions return nil when given nil, instead of crashing the whole program, so returning nil when there's a failure seems to make sense. Or to put it another way, if your database itself were somehow written in Clojure, maybe it would be reasonable to return nil whenever it hits an internal constraint such as field value uniqueness—and devs would be expected to check their constraints beforehand instead of getting errors after the failure.

amacdougall19:01:28

Philosophically, database writes are important. It makes a lot of sense to make sure you're doing the right thing beforehand and treat every error as an emergency. So really, swallowing the exception is bad in both cases; it's just worse in our JDBC system, because an SQLException in a transaction aborts the transaction, and if you don't handle the exception, your Clojure code will be none the wiser.

jaen19:01:45

Anyone knows how to wrangle

(component/using (webserver/make immutant-params) [:application])
into
(-> (webserver/make immutant-params)
  (component/using [:application]))
using paredit? I thought raise would do it, but it substitutes the surrounding form for the one I raise, while I want to keep it around.

jaen19:01:00

(using Cursive's paredit if that makes any difference)

jaen19:01:33

I suppose I could kill the sexp and paste it before the opening paren but that seems... crude.

davidg19:01:47

Ah, because when JDBC throws, it expects the caller to stop what it's doing, either by handling the exception, or not handling it.

amacdougall20:01:52

@davidg: exactly. Just returning nil might make sense in Clojure, though it's debatable. But doing that in a JDBC-based system means that you're ignoring vital context.

jaen20:01:42

Well, nil is never a right option if you need more information that "I cannot return what you want for reasons that will remain a mystery".

jaen20:01:21

So it's equivalent to, say, the Maybe monad - you have a value that's optional.

jaen20:01:36

But if it's not returned there's no additional information besides just that - that is nothing was returned.

jaen20:01:48

If you need to signify what went wrong you need something else, like Either for example - a value that either has a "right" value returned or optionally a value signifying what sort of error happened.

jaen20:01:59

Or you can use exceptions, I suppose, but I'm not a fan of those, unless something so exceptional happens that aborting the application is probably the only recourse.

davidg20:01:33

I spoke up because I've heard it said before that nil is used to mean "error" in Clojure and that this is an impedance mismatch with Java sometimes, but I didn't really know what that means. It seems as simple as that Clojure style is to avoid APIs that throw exceptions and require catching them to use properly. Exceptions can be clunky and are not very FP.

jaen20:01:59

Well, the impedance mismatch is caused by the fact that most Java APIs can't deal with null and will blow up with a NPE, while most Clojure APIs treat nil like Haskell would treat Maybe - that is a something signifying absence of value that functions should ignore and pass unmolested through your program without executing any computations on it.

jaen20:01:04

But there are cases where nil makes sense, and where it does not - for example (retrieve-user id) returning nil is pretty straightforward to understand - no user was found, but what would (establish-connection! host {:timeout 500 :secret "secret"}) returning nil mean? Was the host wrong? Was the timeout reached? Was the secret wrong and server returned a 403?

davidg20:01:42

I understand APIs returning nil instead of throwing BlahNotFound. I hadn't thought about nil propagation being like NaN propagation. So (first nil) returns nil... and going with this style, any function that destructures or operates on data and could possibly pass through a nil should do so...

amacdougall20:01:52

Yeah. In my case, I was returning nil in cases where I expected an SQL error due to violating a table-level uniqueness constraint... which, JDBC aside, is just not a good way to handle it. I'm still doing it, to be honest! I might fix it later. For now, I'm relying on the UI to prevent users to choosing non-unique values, and on unit tests to verify that the constraint exists.

amacdougall20:01:50

I'm not sure about the "right" way to do it. In many languages, you'd catch an exception, or do something like...

result = do_the_operation();
if (result.error) {
  // handle somehow
} else {
  do_useful_stuff_with(result.data);
}

amacdougall20:01:56

But that's not very Clojurey.

davidg20:01:21

It might look ok as a let :keys

jaen20:01:40

That's about how I would do it without resorting to monads.

jaen20:01:45

For example

davidg20:01:08

I think I've written that

jaen20:01:28

(match (something-that-can-fail
  [:success result] (use result)
  [:error error]    (report error)])

Joe R. Smith20:01:36

or return a “tuple”, e.g., [true, nil] or [false, error-map], then you could (let [[success error] (do-operation)] (if success …))

magomimmo20:01:52

I never forget that I’m using a functional programming language, which means I should have an idea about the domain and the range of the function. Those are especially important at the corner cases (I almost test only those corner cases). And I also never forget that at the corner cases is where the fun start, at least in mathematics….

jaen20:01:08

Well, without core.match the tuple way is a bit verbose. But with core.match it's pretty neat.

jaen20:01:55

I guess I still prefer using the Either monad a bit because they compose quite well, in case of the tuple you would have to check it in each function operating on such a value.

cfleming20:01:34

@jaen: Edit-&gt;Structural-&gt;Thread Form is what you’re looking for there, with the cursor right before the form to be threaded (`(webserver/make immutant-params)` in your case)

jaen20:01:55

@cfleming: thanks, that works well for ->, though that's tailored towards threading; is such a general raise-without-substitution not possible then?

cfleming20:01:57

@jaen: Well, anything is possible simple_smile. But there’s nothing like it now, no.

jaen20:01:16

I see. That's probably a fairly weird thing to be wanting to do ; d

amacdougall21:01:47

Fun new question: I'm using the experimental generators in Prismatic Schema to whip up this test data, and—because of the uniqueness constraint I was talking about—I do need unique usernames and emails. But making a lazy seq which hashes with distinct keys is just a short step beyond my knowledge. The distinct function wraps a lazy seq and returns a lazy seq of only the distinct values from it; but I have a lazy seq of more complex hashes (`(repeatedly (partial generate NewUser))`, to be exact). (map first (group-by :username (take 100 (repeatedly (partial generate NewUser))))) easily knocks duplicates out of the 100-user set, but of course I end up with fewer than 100. I have a feeling I'm missing a core language feature that would make this a lot easier... I'm messing around with lazy-seq right now.

amacdougall21:01:08

Looks like the implementation of distinct uses (let [seen (volatile! #{})], so I'll try something like that.

amacdougall21:01:32

Okay, the "volatile" was related to the transducer implementation, so that was irrelevant, but I think I modified it work with my situation. 🎉

meow21:01:09

@amacdougall: not 100% sure what you are trying to do but distinct is a stateful transducer that keeps track of items it's already seen in a volatile set.

meow21:01:55

I think if you did something like (take 100 (distinct (whatever... that you should end up with 100 items

amacdougall21:01:19

The sets of known emails and passwords are simply passed to each further step in the generation. That's roughly what I intended, but I couldn't puzzle out how to write it.

amacdougall21:01:32

This is based on the implementation of clojure.core/distinct, but tailored to my specific needs. There may be a more general way of writing this—for instance, I could pass it a schema and the fields which should be unique. That would cover my own testing needs.

amacdougall21:01:57

(take 100 (generate-distinct NewUser :username :email)) or something.

meow21:01:46

why not (take 100 (distinct (generate NewUser ...

amacdougall21:01:48

The ongoing saga here is that I gave my database a uniqueness constraint on some fields, but now I'm trying to generate test data which conforms to that, so I can test various pagination/etc.

amacdougall21:01:16

Ah, that's because {:username "bob" :color "green"} and {:username "bob" :color "blue"} are distinct, right? The constraint is field-level, but clojure.core/distinct is =-level.

meow21:01:06

sure, whatever would end up in a clojure set

amacdougall21:01:35

At any rate, my tests are all passing now, so I think I'm finally in good shape. Thanks to everyone who kibitzed on my 🦆 session!

meow21:01:40

that's all distinct is doing - memoizing previous items into a set and then checking against that set

amacdougall21:01:11

Yep! In this implementation, I just had to make separate sets of known usernames and emails, instead of distinct's default set of all values.

amacdougall21:01:28

Then for each generated user hash, check both :username and :email against the known sets.

meow21:01:08

so more like a stateful filter

amacdougall21:01:28

Oh, and the trick that I didn't realize is that you can recur within a fn—it just returns to the top of the function! I couldn't figure out how to keep trying generated values until one of them satisfied the distinctness constraint.

meow21:01:32

where either username or password have to be distinct

amacdougall21:01:53

But it's as easy as (recur (next-value) usernames emails).

amacdougall21:01:26

Or as you can see in the gist, more like:

(if (satisfies-constraint)
  (cons item overall-list)
  (recur ...))

meow21:01:37

recur goes back to whatever point you tell it (ie, loop) or I guess defaults to the top of the fn

amacdougall21:01:20

I should have remembered that from The Joy of Clojure, but I only used it in loop for a long time. Guess I forgot!

meow21:01:49

every time I have code with recur it ends up getting changed to into or for

meow21:01:09

I use into way more than recur

amacdougall21:01:27

I'm still getting a handle on some of the finer points. And by "some of" I mean "all of"!

meow21:01:54

And into is so handy since it can take a transducer.

amacdougall21:01:02

Oh, I didn't realize that. Can you give an example?

meow21:01:24

into [] ... into #{} ... into {} ...

amacdougall21:01:47

I mean with a transducer. I've only ever used it to convert between collection types.

meow21:01:03

one sec, I'm looking simple_smile

meow21:01:23

here's a fun, completely generalized fn:

(defn produce
  "Returns a lazy sequence of colls from a recursive, axiomatic,
   transformative process."
  [seed prep-f get-xf]
  (letfn [(process
            [coll]
            (lazy-seq
              (when (seq coll)
                (let [new-coll (into (empty coll) (get-xf coll) (prep-f coll))]
                  (cons new-coll (process new-coll))))))]
    (process seed)))

amacdougall21:01:25

Haha, I can look it up on my own! Just curious if you had one in mind.

meow21:01:36

I'm checking my own code.

meow21:01:21

so I use that produce function a lot in my generative code, passing in various tranducers

amacdougall21:01:09

Interesting—so into composes transducers just like a map / comp structure?

amacdougall21:01:06

Also, that library is blowing my mind just skimming the doc comments. I don't know enough about procedural generation to even begin to use it, but I'm impressed.

meow21:01:37

transducers are composable and into can take a transducer so if you want to give it a transducer that is made up of several you just comp them together.

meow21:01:55

Here is a super simple example:

(defn vert-set
  [mesh]
  (into #{} cat (mp/faces mesh)))

meow21:01:11

cat is a transducer

meow21:01:09

mp/faces just returns vectors of vertices and they get cat'd into a set

meow21:01:46

this isn't using transducers, just regular functions with into, but this is the kind of stuff I find myself preferring over loop/recur:

vnpf-map (into {} (for [vert verts]
                            [vert (into {} (map next-pf
                                                (vert-npfs-map vert)))]))

amacdougall21:01:38

Interesting. Definitely a more functional approach.

amacdougall21:01:33

I'm using Clojure mostly because I like ClojureScript... but I'm still doing relatively simple websites. But it seems like the gain in expressivity really comes to the fore in other domains.

meow21:01:35

Another:

fcolors (into {} (for [face (mp/faces mesh)]
                            (let [color (get-fc mesh face)
                                  color (if color-mod (color-mod color) color)]
                              [face color])))

meow21:01:59

These other examples are from a 3D polygon mesh generating/processing library I'm working on and finding the functional approach to be a real joy. And that's after many years of OO.

amacdougall21:01:00

I've always wondered what language choice says about people. You look at some of the most beautiful and creative computer-generated art, and there's no telling whether the code behind it is a dog's breakfast of C++ or whether it's just as refined as the art itself.

amacdougall21:01:44

I have long since come to the conclusion that the only person who really cares how my code looks is me and maybe 40% of my co-workers, of whom another 20% are sure to get a headache every time they see a higher-order function.

meow21:01:23

Check it out and tell me what you think my attitude is: https://github.com/pkobrien/cad/tree/master/src/cad/mesh

amacdougall21:01:45

Just skimming a few files? I would say balanced. I don't see any obvious duplication; I see the classic FP single-letter variable names used only where there's a conventional meaning for them; I see a lot of the more complex logical steps embodied in long let sequences, which makes them fairly self-documenting.

amacdougall21:01:51

But at the same time, I see lots of uses of declarative and functional programming, where most things are built up from concepts defined earlier on.

meow21:01:13

tell me what you don't like about that code

amacdougall22:01:08

I don't know what I should expect! If you're defining an icosahedron, why not as a nested array of vertices of faces?

amacdougall22:01:45

It seems like it would be hell to edit, but once you get it right, it's not like the definition of an icosahedron is going to change.

amacdougall22:01:01

I was just joking about the "sea of letters" effect.

meow22:01:39

yeah, that code is dense, that's for sure

amacdougall22:01:47

And I'm definitely not usually in the business of analyzing people's personality based on their coding style; although maybe I could pick up some spare change running a fortune-telling booth at conventions.

amacdougall22:01:19

"You put whitespace inside your parentheses... you will go on a long journey soon."

meow22:01:17

here's a transducer with distinct:

(defn normal
  "Returns the normal for the vertex as the average of the face normals."
  [mesh vert]
  (let [face-normal-map (mp/face-normal-map mesh)
        vert-faces-map (mp/vert-faces-map mesh)
        xf (comp (map face-normal-map) (distinct))
        vnorm (fn [vert]
                (->> (vert-faces-map vert)
                     (transduce xf + (mc/point 0.0 0.0 0.0))
                     (mx/normalise!)))]
    (vnorm vert)))

amacdougall22:01:26

Anyway, my test data generation is working and my tests are passing—so I'm going to sign off and enjoy what's left of the weekend! Tomorrow it's back to making cards happen.

amacdougall22:01:38

Thanks for the advice.

meow22:01:49

np, enjoy yourself