Fork me on GitHub
#clojure
<
2015-11-22
>
Tim01:11:31

https://docs.oracle.com/javase/tutorial/sound/capturing.html would you all interface directly with java to capture sound from a mic, or is there a clojure lib?

aaelony01:11:36

Suppose you find a great java library you want to use and not finding a clojure wrapper library extant, you decide to consider writing it yourself. Are there any guidelines that might be followed? any advice? any pitfalls to avoid?

Tim01:11:49

in general? or in my case?

Tim02:11:14

I have no idea, thats one of the reasons why I was asking

ghadi03:11:15

tmtwd: there are some don't's for sure

ghadi03:11:52

don't make dynamic variables to "store" stateful things

ian03:11:44

that's actually something I would like to think about more or have someone else more familiar with the problem space chime in on.

ian03:11:51

as an example, if I just wrap calls to a Java library to make it idiomatic and nicer to use with Clojure, I still lose out on some of the niceties of doing it in Clojure and I fear with any reasonably non-trivial library it will quickly just become Java with lisp syntax and not Clojure inter-oping with Java.

danmidwood03:11:01

Oh, I really wish people would just stop using dynamics

nowprovision05:11:08

I would do (let [[hand new-deck] (split-at 3 @deck)] (reset! deck new-deck) hand))

nowprovision05:11:57

depending on your concurrency story you may need to look into transactions features (out of my depth there)

shriphani05:11:55

Hi, here’s a bit of core.async code. I am trying to wrap a queue (a simple PersistentQueue) with a channel. Another process writes to that data-structure (using swap! conj) however, the recur doesn’t seem to pick up the next item - what am I doing wrong?

nowprovision05:11:07

There doesn't seem to be a problem with your use of recur add some logging to see where its hanging

sveri07:11:12

Hi, how do you do interactive development with seesaw? I tried a very simple snippet with a main function showing a frame (from https://github.com/daveray/seesaw) and then tried to reload it in the repl after changing the text, but nothing happened in my UI. Is there a trick to this?

roelof09:11:25

anyone who can tell me what I did wrong here :

roelof09:11:27

(= 25 ( fn[f] (f 5)) (fn [n] (* n n)))

jaen09:11:29

I dunno, what it is supposed to do? In human words that is?

roelof09:11:22

it's one of the koans

roelof09:11:05

I think it supposed to calculated n * n = 25 , so the answer needs to be 5

ian09:11:19

@roelof: are you missing a set of parens?

ian09:11:32

right now you're just comparing an integer with two fn objects.

jaen09:11:35

Hmmm, so I don't think that's what it does. This

(= 25 ( fn[f] (f 5))
         (fn [n] (* n n)))
is equivalent to this:
(defn [f] (f 5))

(defn [n] (* n n))

(= 25 fn1 fn2)

jaen09:11:41

^what he said

jaen09:11:55

You're just comparing if a function (not the result of it's call) is equal to 25

jaen09:11:21

And functions never equal to anything other than that one specific function instance IIRC.

roelof09:11:44

oke, then I have the wrong answer again

roelof09:11:19

this is the challenge :

roelof09:11:21

"Higher-order functions take function arguments" (= 25 (_ (fn [n] (* n n))))

jaen09:11:54

If that's the challenge then I think ian is correct

jaen09:11:00

You wanted to do the right thing

jaen09:11:03

You just misplaced a paren

jaen09:11:36

((fn [f] (f 5)) (fn [n] (* n n)))

ian09:11:46

@jaen: a small specification to function equality - anonymous functions are all unique, but named functions are not. (= comp comp) evaluates to true.

jaen09:11:31

@ian: yes, that's exactly what I've meant, but the way to put it is certainly more clear.

jaen09:11:49

@roelof: what you're using to write your code?

roelof09:11:17

at this moment light table

jaen09:11:07

I think it has nice syntax highlighting with rainbow parens. They are really helpful - just pay attention to their colour - in your case you gobbled up the ( paren before the _ and it changed the meaning of your form.

roelof09:11:49

oke, one question out of cursioity : can I change the fn part also to a #( ) part

ian09:11:30

they're semantically equivalent, it's just that sometimes it's nice to use one or the other.

jaen09:11:17

Basically if the function is obvious enough you readily understand what %, %2 and so on mean in the context by all means use #(). Otherwise it's probably nicer to use fn and name the arguments.

jaen09:11:34

Oh, and you also can't nest #(), so if you have to have a function within a function - use fn.

roelof09:11:05

oke, I saw a few days ago a discussion about fn against #()

jaen09:11:27

For example compare this change I did in a PR to kioo when fixing something once - https://github.com/ckirkendall/kioo/commit/18838fe504c3e6770752f87503766081746c188d

jaen09:11:46

Which one is more readily understandable, the one with %s, or the one with names?

roelof09:11:27

when you use %2 you have to look every time what %2 is

jaen09:11:25

So yeah, the rule of thumb is (reduce #(* % %2) some-collection) is probably still fine, if the function is more complex - you probably want names.

roelof09:11:58

oke, so first choice will Always be to use fn

ian09:11:28

I would say as a rule of thumb, it's typically nicer to use fn, yes.

ian09:11:12

if the semantic meaning is extremely obvious due to the context or shape of the function, however, using the anonymous reader function syntax (#()) may be a reasonable choice.

jaen09:11:42

Yeah; most of the time I decide to use #() first I then go back and turn it into fn anyway.

ian09:11:02

(defn return-a-fn-that-multiples-by-5 [] #(* % 5)) ((return-a-fn-that-multiples-by-5) 5) would return 25, and, arguably, using (fn [n] (* n 5)) is more noise than it needs to be.

ian09:11:20

that's a very extreme example though, so just use your best judgement. also, as always, it's good to be consistent.

roelof09:11:32

what do you mean with more noise ?

jaen10:11:47

I suppose by noise he mean visual noise and/or confusing code.

ian10:11:16

it's literally more characters is all.

roelof10:11:29

oke, I think I like (fn [n] (* 5 n)) like the most

ian10:11:57

then you should go with that. whatever is easiest for you is best.

jaen10:11:19

Hm, is there any easy way to make all (keyword) keys in schema optional?

jaen11:11:44

@juhoteperi: So this takes care of keys inside things like conditional as opposed to a naive use of clojure.walk, yes?

juhoteperi11:11:38

@jaen: No, optional-keys is not recursive, it only works when given a map schema. There is however schema-tools.walk you could walk over a Schema and then call optional-keys for any maps.

jaen11:11:48

Cool, let me check that out.

jaen12:11:24

@juhoteperi: I've tried this:

(def EventType
  (s/enum :repair-requested))

(def RepairRequestedPayload
  schemas/RepairRequest)

(def Event
  (s/conditional
    #(= (:type %) :repair-requested)
      {:uuid UUID
       :type EventType
       :payload RepairRequestedPayload}))

(def EventQuery
  (st-walk/walk Event st/optional-keys identity))

(s/validate EventQuery {:type :repair-requested :payload {:type :stability}})
and yet I get an error that rest of payload keys are missing. Am I doing something wrong?

juhoteperi12:11:11

@jaen: Unline prewalk ja postwalk, walk is not recursive itself but you would need to call the walk again inside the inner

juhoteperi12:11:35

@jaen: Something like this could work:

clj
(defn recursive-optional-keys [s]
  (st-walk/walk s
                (fn [x]
                  (let [y (recursive-optional-keys x)]
                    (if (plain-map? y)
                      (optional-keys y)
                      y)))
                identity))

juhoteperi12:11:40

Also, could make sense to add prewalk and postwalk to schema-tools

jaen12:11:44

I thought I did it similarly and I NPE'd, let me see what I did wrong.

paulspencerwilliams12:11:59

Hey all, can anyone suggest a baby step to resolve StackOverflows from the attached code attempting to model the sieve of Eratosthenes... https://gist.github.com/paulspencerwilliams/9a5587d9826d1a6e5f94

juhoteperi12:11:37

@jaen: Perhaps you tried to call optional-keys on non-map schema?

jaen12:11:52

Yes, I suspect that's that

juhoteperi12:11:48

I think you want to test for (and (map? schema) (not (record? schema)) to distinguish Schema records from plain maps

jaen12:11:35

Yup, seems to work now, at least for my example case. Thanks a lot!

jaen12:11:52

I don't imagine there's an easy way to have a common part of a conditional schema and have only some keys differ?

juhoteperi12:11:01

The experimental abstract-map Schema does allow something like that

jaen12:11:42

Oh, interesting, I'll look into it.

jaen12:11:43

Since you seem so knowledgeable about schema - do you think there's any way to do conditional coercion (that is a datum is coerced differently depending on the subschema it is in) with schema, or would I have to do it on top of that (by wrapping the values so I can differentiate them, or coercing separately)?

juhoteperi12:11:35

Hmm, the first option might be possible using dynamic binding, but I'm not sure

jaen12:11:47

But that would only work in Clojure then, right? I guess I'll look into generating new schemas using the walker that would attach contextual information to relevant keys or something of the kind (because I don't think I'll be able to understand schema code well enough to modify it to let coercer get context information).

jaen12:11:51

Thanks for all the help!

jaen15:11:26

(s/defn test [a :- s/Int]
  (+ 2 a))
=> #'boot.user/test
(test 2)
=> 4
(test "derp")
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

jaen15:11:32

Is that the expected behaviour?

jaen15:11:39

It seems as if the schema annotation is ignored.

jaen16:11:35

@ragge: thanks, wasn't aware of set-fn-validation!, I've only used schema for input/output validation & coercion, never for functions.

paulspencerwilliams17:11:34

sreenath.n: cheers, just reading code now

jstew19:11:02

Anyone using chime to schedule jobs? I can't seem to figure out how to pass in job data other than use global state. Which won't work for me.

jstew19:11:44

cronj is nice, and I already started using it. I need to add a range of random seconds to the start of each job which is what made me look at chime.

jstew19:11:24

I can do the same with cronj, but have to start the job then sleep or timeout for a few random seconds but I don't want to do that if possible.

dm320:11:05

@jstew, I used cronj with an additional R pattern in the job schedule spec, e.g. R 0 0 *, where R was substituted with an (rand-int 60) before passing the spec to cronj. Didn't try chime...

jstew21:11:44

@dm3 - nice! I didn't think about doing text substitution. That might work.

jstew21:11:54

There's also quartzite but I kept swearing about it's verbosity.

jaen22:11:03

I quite like Immutant's scheduling library

jaen22:11:34

Though I don't know how it compares to Quartzite power-wise