Fork me on GitHub
#clojure
<
2017-08-03
>
joshjones00:08:40

@schmee Yes I remember being confused one time because this didn't work:

(let [[x y] #{:a :b :c}] x)
but this does:
(let [[x & y] #{:a :b :c}] x)
makes sense, but was confusing at the time

schmee00:08:51

in my case above, w is (was) actually a lazy seq created with for

schmee00:08:22

so I don’t get why destructing the rest is so slow 😕

bradcypert00:08:49

Quick question: What’s the practicality for (declare x) ?

noisesmith00:08:19

to be able to use definitions higher in the ns than defined

bradcypert00:08:19

I have a function that depends on a symbol later in the file, I was curious if declare makes sense to be used here, or if there’s a better way.

noisesmith00:08:28

that's what declare is for

bradcypert00:08:33

Gotcha, thank you 🙂

pelletier01:08:29

any known way to work around the limitation of async/go not seeing <! and >! calls when working with a complex piece of code?

noisesmith01:08:24

complex as in the <! and >! are inside functions? that's not meant to work

pelletier01:08:06

yeah, as in <!/>! are a few calls deep

noisesmith01:08:53

go is a macro, macros operate by rewriting code, it shouldn't be trying to rewrite code inside functions

noisesmith01:08:42

those <! and >! calls work because go knows how to translate them into a state machine that integrates with channel machinery, it would be an overreach to rewrite the code of arbitrary functions called inside the block

pelletier01:08:22

that's pretty much where i got. i'm trying to find an alternative to perform channel-based communication between workers that does not involve rolling my own thread scheduler

noisesmith01:08:22

if you look at the functions defined in core.async itself, you'll see a general pattern of passing channels to functions and then parking on the channel (or getting a channel back from a function)

noisesmith01:08:41

of course this involves the function calling go inside, most of the time

lincpa01:08:08

My project run " lein trampoline repl " on Clojure 1.9.0 Alpha 14 or 1.9.0 Alpha 15 is ok, but on 1.9.0 Alpha 16 or 1.9.0 Alpha 17 is error: Exception in thread "main" java.io.FileNotFoundException: E:\temp\form-init820515111953380484.clj (The system cannot find the specified file. ) at java.io.FileInputStream.open0(Native Method) at java.io.FileInputStream.open(FileInputStream.java:195) at java.io.FileInputStream.<init>(FileInputStream.java:138) at java.io.FileInputStream.<init>(FileInputStream.java:93) at clojure.lang.Compiler.loadFile(Compiler.java:7392) at clojure.main$load_script.invokeStatic(main.clj:277) at clojure.main$init_opt.invokeStatic(main.clj:279) at clojure.main$init_opt.invoke(main.clj:279) at clojure.main$initialize.invokeStatic(main.clj:310) at clojure.main$null_opt.invokeStatic(main.clj:344) at clojure.main$null_opt.invoke(main.clj:341) at clojure.main$main.invokeStatic(main.clj:423) at clojure.main$main.doInvoke(main.clj:386) at clojure.lang.RestFn.applyTo(RestFn.java:137) at clojure.lang.Var.applyTo(Var.java:702) at clojure.main.main(main.java:37)

noisesmith02:08:33

@lincpa maybe you have LEIN_FAST_TRAMPOLINE set in your environment and your .lein_classpath file captured a file that was generated but no longer exists?

noisesmith02:08:38

just a theory

lincpa02:08:02

@noisesmith Thanks, " lein repl" on Clojure 1.9.0 Alpha 17 is ok!

zilti06:08:16

@pelletier also, a (go ...) block always returns a channel which will return the result of its inside as its sole value.

hmaurer10:08:12

Hello! I have having a very strange issue where a for construct appears not to be executed inside the body of a function called by a test and I have no idea how to debug it

hmaurer10:08:49

I boiled down the problem to these three lines:

(println "here")
(map #(println %) (range 5))
(println "there")

hmaurer10:08:02

When running the test, “here” and “there” are printed, but nothing is printed in-between

hmaurer10:08:22

(same if I used (for [x (range 5)] (println x)))

hmaurer10:08:37

I have absolutely no idea what could be interfering with the iteration. The test is executed within a larger context (it’s running a query on a graphql schema handled by lacinia, and this function is called as part of the resolve process)

hmaurer10:08:03

mystery solved

hmaurer10:08:07

it yields a lazy sequence

hmaurer10:08:16

doall fixes it

hmaurer10:08:39

I don’t have internet at home at the moment and this kept me awake for an hour and a half yesterday 😄

drowsy11:08:41

@hmaurer if you don't need the seq but only the side effects you could consider dorun as it does not hold onto the head.

hmaurer11:08:03

@drowsy ah, good point. thank you!

drowsy11:08:31

also you could have a look at doseq which basicly is for for side effects

hmaurer11:08:17

@drowsy precisely what I was looking for, thank you. Basically I want to loop through a collection, do a check on each member and throw an exception in some cases

jfntn13:08:07

I’ve a global private map in an atom used as a key-value cache, are there any reasons why I wouldn’t want to make that map a transient?

jfntn13:08:45

Seeing perf benefits from faster assoc!, but thinking I might be missing some potential issues

leonoel13:08:31

@jfntn terrible idea

leonoel13:08:28

swap! may retry to assoc! in case of contention, you will end up with a corrupted map

jfntn13:08:10

Ah good point, is it correct that this would not apply to cljs?

leonoel13:08:43

atom in cljs behaves pretty much like an ordinary variable

leonoel13:08:22

there's no compare-and-swap like in clj

jfntn13:08:38

Are there other mutable containers that'd perform better than this in cljs?

leonoel13:08:17

not in the standard library

leonoel13:08:28

maybe javascript arrays or objects could do the job if keys are strings or numbers, otherwise you'll have to implement clojure equality semantics yourself

jfntn13:08:41

Interesting, thanks @leonoel

pwrflx15:08:54

hi! how to have a spec that restricts a string to be between X and Y length?

henrik15:08:08

Is it possible to use spec to search a data structure and return matches for a regex? Ie., equivalent to re-find.

mpenet16:08:44

@pwrflx (s/and string? #(<= your-min (count %) your-max))

pwrflx16:08:24

@mpenet thanks! btw will test data generation work in case of such hand-written predicates?

kwladyka16:08:32

What is the simplest way to pretty print XML? I just need to put XML in readable format for user

mpenet16:08:54

@pwrflx yes, it might take a while depending on your bounds, in that case you can pass a custom generator

pwrflx16:08:13

@mpenet will give it a try, thanks!

mpenet16:08:22

but you can test it with (s/exercise (s/and string? #(<= 0 (count %) 100))) for instance

kwladyka18:08:21

yeah i saw it, but i am curious if it can be simpler 🙂

qqq17:08:01

is http://repo1.maven.org being slow for anyone else?

michaelblume17:08:20

(-> xml-string java.io.StringReader. clojure.data.xml/parse clojure.data.xml/indent-str)

kwladyka18:08:09

yes, i discovered this method, but it is not exactly this, but with the same effect on the end 🙂

michaelblume17:08:39

maybe throw in a println at the end

xiongtx19:08:08

I’d like to turn the following into a macro:

(defn until-equal
  ([func]
   (until-equal func (atom {:init false :val nil})))
  ([func prev-atom]
   (until-equal func prev-atom 10))
  ([func prev-atom n]
   (if (neg? n)
     (throw (Exception. "Cannot achieve equal values"))
     (let [prev (if (:init @prev-atom)
                  (:val @prev-atom)
                  (func))
           current (func)]
       (if (= prev current)
         current
         (do
           (swap! prev-atom assoc :init true :val current)
           (recur func prev-atom (dec n))))))))
The basic idea is that some func (e.g. rand-int) is evaluated until two results in a row are equal. Instead of func, however, I’d like to have some unevaluated & body. However, I’m not sure how to resolve the recursive macros problem.

bfabry19:08:07

loopdyloop

bfabry19:08:33

you could just take your until-equal function, and create a macro (defmacro until-equal' [& body] `(until-equal (fn [] ~@body))) 🙂

bfabry19:08:59

I'd suggest that using atoms is a really un-clojurey way to do this btw

noisesmith19:08:35

why is that atom in there?

noisesmith19:08:51

oh, what he said - the atom is kind of pointless in this code btw

noisesmith19:08:28

unless you expect to call the function from multiple threads concurrently and want to stop when two calls are equal even though they are from different call sites…

noisesmith19:08:35

stateful functions are weird

bfabry19:08:23

(loop [prev-value (func) lim-counter 10]
  (when (< lim-counter 0) (throw (Exception. "Cannot achieve equal values)))
  (let [next-value (func)]
    (if (= prev-value next-value)
      prev-value
      (recur next-value (dec lim-counter)))))
^ that is how I'd write until-equal without atom confusingness

noisesmith19:08:42

a more functional style

> (->> #(rand-int 10) (repeatedly) (partition 2 1) (drop-while (partial apply not=)) (ffirst))
2

bfabry20:08:11

I'd quibble over more "functional". utilising laziness is definitely a functional thing to do but a recursive loop isn't exactly imperative

noisesmith20:08:34

how about “declarative”

bfabry20:08:47

declarative is exactly it

misha20:08:51

@noisesmith how often should I worry about cost of such fns built from clojure.core/ ones?

misha20:08:28

(Talking about you drop-while example above)

noisesmith20:08:53

what do you mean by “built from clojure.core ones” - the partial?

noisesmith20:08:50

@misha anyway, typically the most readable / maintainable code will be the code that uses lazy features (like that example), the best performing will use reduce (if it consumes a collection that is) with loop being the least readable / maintainable and in the middle perf wise

noisesmith20:08:37

the thing you really want to look out for is sloppy mixing of eager and lazy (eg. calling concat in a loop or reduce to build up a value) - that’s where the dragons are

noisesmith20:08:39

you have the twin problems of space / stack usage going out of control or correctness being lost when lazy and eager code are mixed poorly

misha20:08:12

I declare the answer — accepted! opieop thank you

misha20:08:42

I think it is really good advise

qqq20:08:58

I'm starting my webserver as:

(defn launch-dev []
  (org.httpkit.server/run-server 
   #'app 
   {:port  5001
    :join? true}))
however, when I try to connect to it, I get:
telnet localhost 5001
Trying ::1...
Connected to localhost.
Escape character is '^]'.
GET /
Connection closed by foreign host.
How do I debug this?

bfabry20:08:30

I mean.. lazy sequences and utilising reduce is cool and all. but I find it hard to believe anyone would find my loop example less readable than either the lazy seq implementation or a reduce example

noisesmith20:08:13

I’m not trying to pick on that code, the main thing I wanted to get at was that generally when consuming something that can be treated as a sequence, one of clojure’s higher level sequence consuming functions will be more straightforward to read. reduce is often weird (especially if one is less used to using it) but it does perform better

schmee21:08:44

I’m mucking around with core.match, and I’m wondering why it’s using try/catch to implement backtracking, instead of say, case or something

schmee21:08:27

I’ve read on the internet that exceptions are “slow” opieop

hiredman21:08:42

core.match has an a graph that represents the match and it needs to flatten in to a tree because clojure code is a tree

hiredman21:08:45

one way to flatten it would be to copy the nodes that get looped back to every place that would get looped back to

hiredman21:08:56

(which is likely what you mean by using case)

hiredman21:08:26

the problem with that is when you copy like that the code size explodes

hiredman21:08:28

so what core.match actually does is use an exception to jump back to another node (pre-allocated exceptions are apparently pretty fast on the jvm)

hiredman21:08:51

the algorithm core.match is based on sort of assumes gotos or tail calls in the output language, neither of which clojure has

schmee21:08:30

interesting!

schmee21:08:32

so backtracking / exceptions are use to reduce code size?

schmee21:08:36

I tried macroexpanding the fizzbuzz example from the readme with *no-backtrack* bound to true, and it actually made the expanded code smaller

schmee21:08:01

admittedly that is a simple example

schmee21:08:15

very nice read, feels good to set your misconceptions straight, thanks!

lxsameer22:08:43

does any one uses aleph in production ? I'd like to know about your experience

noisesmith22:08:19

I’ve never had a problem

noisesmith22:08:35

replacing the previous jetty was easy, and it’s never misbehaved

lxsameer22:08:06

nice, what about documentation ?

noisesmith22:08:37

it’s pretty well documented via the github page