Fork me on GitHub
#clojure
<
2016-06-09
>
triggernz01:06:40

clojure newbie here

triggernz01:06:20

what is the best testing framework to start a new project with?

noonian01:06:10

@triggernz: clojure.test is built-in to Clojure. Thats what I’d recommend.

triggernz01:06:01

yeah cool. i thought as much but thought i'd check 🙂

thug.nasty01:06:51

I second clojure.test

superstructor02:06:27

@triggernz: clojure.test, also org.clojure/test.check and clojure.spec

andmed06:06:26

Looks like an error on 4clojure: this code

((fn [col x]
       (vec (vals
              (filter #(not= (mod (key %) x) 0) (zipmap (iterate inc 1) col)))))
     [1 2 3 4 5 6 7 8] 3)
gives => [1 2 4 5 7 8] but [8 7 5 4 2 1] there. Cant pass test because of that. Would be ice to fix 🤓

hiredman06:06:47

your code is relying on the seq order of an un-ordered collection

hiredman06:06:54

4clojure is running an old version of clojure, between it and the version of clojure you are running your code on, clojure changed how it hashes things, which changed the internal structure of collections based on hashing, which changed the order of their seqs (which was not guaranteed to be in any particular order)

seancorfield06:06:58

...which was never guaranteed to be in any particular order? ^ @hiredman

bcbradley07:06:55

when do you think it would be wise to use (comp ...) instead of (-> ...) ?

hiredman07:06:59

-> is a rewrite of syntax, comp is function composition

bcbradley07:06:40

they both are capable of composing functions

bcbradley07:06:05

doesn't -> feed the output of one of its arguments into the next?

hiredman07:06:14

-> does not compose functions, it rewrites syntax, the effect can be similar but it is different

bcbradley07:06:22

thats what i am asking

bcbradley07:06:29

when would it be best to use -> vs comp

bcbradley07:06:39

i mean i know if i strictly need a composed function as an entity

bcbradley07:06:42

obv comp is the way to go

hiredman07:06:45

-> doesn't feed outputs, it can't when it runs there are no outputs, just forms

bcbradley07:06:47

but i'm talking about where they overlap

bcbradley07:06:23

i don't think i understand that

hiredman07:06:40

-> is heavily favored over comp in places where you could use either

mpenet07:06:50

in short: comp is runtime, -> compile time

bcbradley07:06:57

ok that makes sense

bcbradley07:06:19

so, on an unrelated note

bcbradley07:06:21

is -> a macro?

mpenet07:06:23

ex you cannot (apply -> [])

mpenet07:06:26

yes it's a macro

mpenet07:06:12

usually -> is better (no runtime cost), use comp when you have no other choice, or when it makes more sense (ex xforms)

hiredman07:06:32

((-> a (fn [] a)))

bcbradley07:06:51

so if you were in a situation where you needed to take a function as an argument to another function, and you wanted to be able to "compose" different functions to form the argument, and had a choice between -> and comp, you would have to use comp?

bcbradley07:06:18

since -> is a macro, not a function?

mpenet07:06:22

depends if you know the composition at runtime/compile time

bcbradley07:06:04

take keybindings for a video game for example

bcbradley07:06:17

you might want to have keys associated with actions

bcbradley07:06:33

like wasd, goes up down left right

bcbradley07:06:53

you'd want the behavior to be composed, so a person can press both w and d at the same time to go up and right at the same time

bcbradley07:06:07

if the game hardcoded the wasd, then you could use ->

bcbradley07:06:18

if you want to let the user change the keybindings on the fly, you'd have to use comp?

mpenet07:06:47

not really, it's another unrelated problem (handling state)

bcbradley07:06:49

the "compile time" vs "run time" is confusing to me

bcbradley07:06:58

i know what that means, but i can't see how it applies

mpenet07:06:03

-> just rewrites code for you

bcbradley07:06:12

oh ok that is much more clear

mpenet07:06:15

comp effectively creates a new function out of N functions

bcbradley07:06:19

of course thats what macros do

bcbradley07:06:56

if you use (def blah (comp ...)) is there really a big difference?

mpenet07:06:00

I use to teach the -> functions with drawings full of arrows moving stuff around, it's easier to understand

mpenet07:06:52

small performance difference I bet, but probably irrelevant in your case

bcbradley07:06:14

ok so i think i'm starting to understand it a bit better

mpenet07:06:33

as I said, if you dont really need runtime "composability" just use ->

bcbradley07:06:53

can you give an example for which you might want run time composibility?

bcbradley07:06:59

so i can understand it more concretely?

mpenet07:06:06

(apply comp [...])

mpenet07:06:14

where the list of functions is not pre-determined

mpenet07:06:31

could be from a function argument for instance, passing a coll of fns

bcbradley07:06:38

wow thats pretty abstract, i had never thought of doing anything like that before

mpenet07:06:53

or with transducers

bcbradley07:06:15

i studied transducers quite a bit

mpenet07:06:21

(map (comp fn1 fn2 fn2))

bcbradley07:06:34

it feels like there is a relationship between transducers and comp

bcbradley07:06:45

is that because transducers compose as functions?

mpenet07:06:40

well you need a function, then the way you get to that doesn't really matter, but comp is one of the most obvious choices

bcbradley07:06:01

could you say (comp transducer1 transducer2)

mpenet07:06:12

could be an anonymous function using -> too, doesn't matter #(-> % fn1 fn2)

bcbradley07:06:06

so to take what you said earlier, -> would be better for that too, unless you needed to be able to compose an uncertain number of transducers in an uncertain order at runtime

andmed07:06:25

@hiredman: awesome, that makes sence, thank you

bcbradley08:06:49

i can't figure out this error message

bcbradley08:06:59

why doesn't this compile?

bcbradley08:06:00

(defn update-me [we i] (apply comp (map #(partial % we) (:functions i))))

bcbradley08:06:18

i is a map, we is an array of maps

bcbradley08:06:49

the maps contain a key :functions with the value being an array of functions

bcbradley08:06:47

the functions must each take two arguments of the form [we i]

bcbradley08:06:17

for example (defn print-me [we i] (println i) [i])

rauh08:06:01

Can you show and example invocation?

m1dnight08:06:00

And the actual error message might come in handy too 😛

bcbradley08:06:53

srry computer crashed, the error message is "don't know how to create ISeq from: clojure.core%partial%fn_4759"

bcbradley08:06:28

I think i might know what is going on though, these functions return vectors

bcbradley08:06:58

but after the partial, they expect "i" to not be a vector

bcbradley08:06:18

so i guess trying to compose those partials is the problem

m1dnight08:06:32

Glad I could help! >:)

devth13:06:49

when a namespace is required, if it has a -main, is -main automatically invoked?

plexus13:06:00

no, but if the namespace is compiled as a class, then that function will be the main function of the class

plexus13:06:24

or if you set that namespace as :main in project.clj, then lein run will run it

rickmoynihan14:06:03

Hey... I've been very pleased with clojure.spec, which looks absolutely fantastic, and a nice step up from plumatic.schema - and I am fully intending to play with it properly (I've only really had time to read the announcement, listen to Rich on the cognicast, and looked at a few examples)... Anyway, one thing I'd really like to do is understand how this fits with JSON schema... Now, clojure.spec is clearly far superior to JSON schema, but it's not used by the javascript community etc... So I was wondering if anyone has thought about how one might be able to build a JSON schema from a clojure.spec. As spec is way more expressive, I'm guessing that to do this you'd have to stick to a subset of spec (and I guess you could probably use clojure.spec to specify that subset)... The basic idea would be to write a super-spec in spec; and output JSON schemas to interoperate with other tooling/libraries in other languages etc... e.g. swagger clients etc.

rickmoynihan14:06:15

but obviously from within clojure you'd be able reuse that subset of spec (which generated JSON schemas), and layer ontop the additional expressivity and specs you'd want clojure side.

rickmoynihan14:06:06

Sorry - just seen there's a #C1B1BB2Q3 channel - reposting the above there.

ghaskins15:06:16

Hi All, I have a question about macros…first some background: I have a need to interface with a nodejs library and love clojure so I figured I would give clojurescript a try (I know this is not #C03S1L9DN but my question is more about defmacro in general)

ghaskins15:06:12

so, I started working with the nodejs library and quickly was annoyed with the callback hell and thought I would take the opportunity to learn a few things I’ve been meaning to pick up like core.async and defmacro

ghaskins15:06:36

I was inspired by https://github.com/gilbertw1/cljs-asynchronize, but it didnt do quite what I wanted…I figured this was a good opportunity to learn

ghaskins15:06:09

what I wanted was something as follows: say I had some form with a callback pattern, like (form-with-callback param1 param2 (fn [resp] (do-next-thing resp)))

ghaskins15:06:24

say my macro is called “syncexec”, so that could become (syncexec (form-with-callback param1 param2 …)), which would evaluate to “resp” from the callback

ghaskins15:06:24

I more or less got everything working but I ran into somewhat of a chicken-egg problem and I am starting to come to the conclusion that it cant be done, heh

ghaskins15:06:30

but, I didnt want to give up that easily

mccraigmccraig15:06:49

@ghaskins: promise-monad will sort you out nicely

ghaskins15:06:05

oh! ill check that out thank you

mccraigmccraig15:06:27

hold on.. i'll give you some reading @ghaskins

mpenet15:06:21

ghaskins: I wrote a simple macro to do something similar for jayq back in the days, expands as a sort of "let" form (akin to what "do" notation would look like in haskell): https://github.com/ibdknox/jayq/blob/master/src/jayq/macros.clj#L15-L36

mpenet15:06:58

then you could write

(let-deferred
    [a (jq/ajax "")
     :let [foo "bar"]
     :when (= (concat a foo) "foobar")
     b (jq/ajax "")]
(merge a b foo))

mpenet15:06:46

the plumbing is usable to write other let-* macros like this

mccraigmccraig15:06:22

@ghaskins: http://funcool.github.io/cats/latest/#mlet can be used with a bunch of different promise-monad implementations...

mpenet15:06:35

cats is surely way nicer

mccraigmccraig15:06:06

not sure where it's gone in v1.3 though

ghaskins15:06:02

will check it out for sure

ghaskins15:06:44

I guess for my own learning, it would be interesting to discuss what I ran into if anyone is willing

ghaskins15:06:28

the basic problem I was having was that I needed to take the passed-in form, replace the ‘…’ with something that closes on a core.async/chan, run the original-form in a go block, and then block on the channel waiting for a response before returning

ghaskins16:06:39

the problem was I was constantly wrestling between the runtime/compile-time evaluation of the channel

ghaskins16:06:34

If I deferred the eval deep enough in the form to satisfy the synthesis of the target form, I had trouble extracting the channel I needed to wait for….if I did it early enough to know what to wait for, evaluating the synthesized form became impossible because it seems you cant use references like ‘#object’ in an (eval)

ghaskins16:06:40

its quite possible that I was simply asking for something that cant easily be expressed in clojure, but I have a gut feeling I just lack the sophistication to pull it off 😉

ghaskins16:06:01

i could share code

caio16:06:00

in clojurescript*

caio16:06:52

if i understood what you wanted to do, in clojure you could do this:

(defn syncexec
  [f & args]
  (let [ch (chan)]
     (apply form-with-callback args
            #(go (>! ch %)))
     (<!! ch)))
and call it (syncexec form-with-callback param1 param2) to return the result the callback would receive

caio16:06:59

you can do nasty stuff and use refs to synchronize them as well i think (but idk how this works in clojurescript)

caio16:06:46

(defn syncexec
  [f & args]
  (let [s (atom {:res nil
                 :ready nil})]
     (apply form-with-callback args
            #(reset! s {:res %
                       :ready true}))
     (loop [ready (<@U06QXASV8> :ready)]
       (if ready
         (<@U06QXASV8> :res)
         (recur (<@U06QXASV8> :ready))))))
no macros needed as well

caio16:06:06

and should work on cljs

ghaskins16:06:07

@caio: ah, that is interesting…i hadnt thought of collapsing the syncexec and form-with-callback

ghaskins16:06:31

but I see where you are going with that

ghaskins16:06:41

I was running into problems because I could easily process the form to synthesize callbacks where the ‘…’ appeared, but then had trouble actually doing something with it

ghaskins16:06:54

but (apply) might allow me to work around that

ghaskins16:06:17

thank you for all the ideas everyone

mhr16:06:35

is using #() more common than using (fn [] ...)?

mhr16:06:14

I'm trying to figure out what's idiomatic for lambdas. I discovered last night that you can't embed a sugary lambda within another sugary lambda #(#()), the interpreter doesn't allow it, so it's less powerful.

noonian16:06:21

Only for very short functions. You can’t nest the shorthand syntax and it is arguably less readable.

mhr16:06:16

noonian: I personally find them less readable if there are arguments so then you have to number your percents. I'm a beginner, so maybe I'll just become used to it. If I never use them in my code, would that be fine?

noonian16:06:35

mhr: Yes it is perfectly okay to never use the shorthand version for anonymous functions 🙂

dg17:06:24

I only use #() when it's not only short but also simple

cddr17:06:10

I'm wondering about the recommendation to not include lein in an application's production host. Does this still make sense if you're building your app in a docker image?

mpenet17:06:37

Imho yes. It's also a matter of having less potential for breakage (possibly broken dependencies, unavailable clojars etc)

Lambda/Sierra17:06:01

Leiningen is a development tool. It injects lots of extra stuff: REPL libraries, JVM command-line arguments optimized for startup time over runtime performance.

cddr17:06:49

OK Cool. Didn't realize it tweaked JVM options.

octahedrion19:06:18

why

user=> (realized? (iterate inc 0))
true

octahedrion19:06:48

when iterate "Returns a lazy sequence" and realized? "Returns true if a value has been produced for a promise, delay, future or lazy sequence."

octahedrion19:06:24

ok I just answered my own question

octahedrion19:06:54

but what meant was (iterate inc 0) isn't realized

octahedrion19:06:14

so is there a way to determine if an object is a lazy-sequence ?

gfredericks19:06:51

blackblock: why do you need to?

bsima19:06:03

is do the same thing as a lambda? it says its implemented as a special form, but as far as i can tell it has the same semantics as a normal function call

gfredericks19:06:26

it's just for combining things together

gfredericks19:06:50

to "do" sequentially

bsima19:06:11

yeah but you can do that with a lambda, no need for a do special form. it seems redundant

gfredericks19:06:23

you mean ((fn [] (one thing) (another thing)))?

gfredericks19:06:02

it's probably special so the compiler can easily not compile it as function calls

gfredericks19:06:16

let is redundant in the same way

gfredericks19:06:25

and probably for the same reason

bsima19:06:28

yeah i figure thats the only reason to implement it as a special form

gfredericks19:06:45

I don't know of any other

hans19:06:12

bsima: the reason is probably optimization. do is trivial, fn is much more involved, and to optimize away the effort of a fn that is just there to imitate a do is significant.

ghadi19:06:21

fn parses its body as an "implicit do"

ghadi19:06:18

"BodyExpr" is a do

hiredman19:06:56

actually, if you implement let and do as functions you can't have recur

gfredericks19:06:04

is it just because recur is ambiguous or does it mess it up more than that?

octahedrion19:06:07

@gfredericks: no reason, just wondered

hiredman19:06:54

a large part of the work that optimizing compilers do for scheme (which generally do implement stuff in terms of lambdas) is actually recovering the distinction, lambdas that are invoked immediately and don't escape can be compiled more effeciently

gfredericks19:06:08

blackblock: a lot of times you should be able to get away with not needing to know

bronsa19:06:59

@hiredman: interestingly Compiler.java does the opposite by lifting some loop bodies into fns to help the JVM JIT

octahedrion19:06:35

@gfredericks: ok but say i did need to know ?

hiredman19:06:40

is that why the compiler does that? I just assumed it was to make the compilers job easier

hiredman19:06:36

expression semantics for a goto and a bunch of labels is tricky, but if you hoist it out as a function you automatically get it by invoking the function

gfredericks19:06:02

blackblock: chehcking the class is probably the easiest way; in this case, iterate used to return a lazy seq, but now it returns an ad-hoc optimized type, so I'm not sure whether the current docstring should be considered accurate

bronsa19:06:16

@hiredman: I don't remember the specifics but I remember cgrand talking about it in some JIRA ticket and that was the reason he gave -- I didn't have much trouble in t.e.jvm emitting expr loops w/o wrapping them in once-only fns

hiredman19:06:27

I guess I should remember that

bronsa19:06:39

it's not much to go on but I remember I did some digging and found a few conversations in the early days of the clojure ML that talked about it

gfredericks19:06:10

blackblock: no, returns true for lists

gfredericks19:06:59

I think the type hierarchy is complicated enough that there's probably not an objective answer, you have to say what you're trying to do first

octahedrion19:06:06

user=> (realized? (take 7 (iterate inc 0)))
false
user=> (realized? (iterate inc 0))
true

octahedrion19:06:30

well i'm interesting in detecting if something's infinite

gfredericks19:06:45

oh I don't think that's generally possible

ghosss19:06:55

that's the halting problem 🙂

bronsa19:06:03

(cons 1 (range))

octahedrion19:06:42

hmm vs (cons 1 '(2 3)) ok

gfredericks19:06:29

(defn goldbach-counterexamples "Returns a lazy seq of positive even integers that can't be expressed as the sum of two primes." [])

gfredericks19:06:20

⇑ not only would not know whether that's infinite, you wouldn't know how long it would take to realize the first element, if ever

octahedrion19:06:02

i know (range) is

octahedrion19:06:21

i know (iterate inc 0) iss

octahedrion19:06:33

because of their types

gfredericks19:06:06

(defn infinite? "Returns :yes, :no, or :dunno" [coll max-runtime])

gfredericks19:06:40

now if only you could reliably kill jvm threads it'd be easy to write that

hiredman19:06:42

what about the types of those things do you think is telling you something about if it is infinite or not?

gfredericks20:06:04

hiredman: I'd bet clojure.lang.Iterate is always infinite

octahedrion20:06:19

well if the object says it's infinite and you cons something on to it

octahedrion20:06:27

you can infer the result is too

octahedrion20:06:53

so maybe in certain limited cases it's possible

bronsa20:06:44

@octo221: (range 0 1) isn't infinite

gfredericks20:06:05

bronsa: it has a different type

octahedrion20:06:09

good counterexample

bronsa20:06:21

@gfredericks: right, but that's an implementation detail :)

hiredman20:06:41

and over the life of clojure it has returned different types

octahedrion20:06:11

so you can't rely on checking types ?

octahedrion20:06:27

of course not

bronsa20:06:29

not unless the function makes a promise about the returned type, and I don't think any do

octahedrion20:06:55

implementations change ok

hiredman20:06:56

well, they make vague hand wavy seq promises

octahedrion20:06:31

eh well learned something there thanks!

hiredman20:06:13

chapter 4 of http://repository.readscheme.org/ftp/papers/orbit-thesis.pdf is "Closure Analysis" which is about taking all the lambdas in a scheme program and figuring out if they actually need to be function objects, or just stack manipulation or whatever

octahedrion20:06:59

wait so there's no way for a fn to signal that it will return an infinite sequence ?

octahedrion20:06:11

(sorry to go on about this)

hiredman20:06:30

there is no way to tell the difference between a lazy seq that terminates and one that doesn't besides walking it

octahedrion20:06:54

no i get that but

octahedrion20:06:30

isn't there a way that the fn definition can mark itself as returning an infinite seq

octahedrion20:06:45

no i guess not

octahedrion20:06:00

wait maybe spec can do that ?

hiredman20:06:10

there are about a million ways you could mark a function you write

octahedrion20:06:21

can spec say that about a fn ?

hiredman20:06:23

the name, some metadata, a comment, etc

hiredman20:06:31

but what do you expect that to do?

octahedrion20:06:32

yeh ok metadata

octahedrion20:06:07

eh ok i'll drop it thanks

hiredman20:06:11

some functions will return a infinite seq or a terminating seq based on their arguments

hiredman20:06:25

some functions will return seqs based on requesting external resources (http requests or database queries) and their termination or not may depend on what is returned from the external resource

octahedrion20:06:44

yeh i'm not interested in side effects

octahedrion20:06:55

or halting problem

octahedrion20:06:05

only what fns say they are

octahedrion20:06:22

their being infinite is just one example

octahedrion20:06:30

could be any quality

octahedrion20:06:43

it's a question of types really

octahedrion20:06:57

anyway too vague

thomas20:06:12

Hi.. I am stuck on something I don’t under stand:

thomas20:06:27

Why doesn’t my function take two arguments? I just don’t understand. I suspect I am doing something wrong.

loganmhb20:06:08

You are passing 1 argument to an anonymous function somewhere in nearest-stop that needs 2 arguments, it looks like.

loganmhb20:06:25

note geo-code/nearest-stop/fn—2828 vs geo-code/nearest-stop

loganmhb20:06:04

(or needs more than 1 argument, at any rate)

thomas20:06:34

aaah ok… I see what you mean.

loganmhb20:06:16

happy to help!