Clojurians
#clojure
<
2015-11-18
>

This page is not created by, affiliated with, or supported by Slack Technologies, Inc.

mrg03:11:49

Could somebody tell me what the #' reader macro is used for in Clojure?

mrg03:11:03

I know in Lisp-2s it's used to look a symbol up in the function scope

mrg03:11:19

but with Clojure being a Lisp-1... is it just an optimization?

roberto03:11:50

When used it will attempt to return the referenced var. This is useful when you want to talk about the reference/declaration instead of the value it represents.

mrg03:11:43

Thanks @roberto

mrg03:11:56

yup, that answers it! Great, thank you!

roberto03:11:37

you’re welcome

chancerussell03:11:12

Anyone know of a nice, clean way of handling “wrap this value in a sequence IFF it isn’t a sequence”?

chancerussell03:11:54

Either that or a function that either concats or conjs based on the input :stuck_out_tongue:

roberto03:11:08

(when (seq? v) (seq v)) ??

bostonaholic05:11:51

wouldn't it be (when-not (seq? v) (seq v))

dchelimsky05:11:04

@chancerussell: guessing from your two questions, I think you're probably looking for a solution to the latter (the former in support of the latter). Correct? One way to re-prhase that is that you want to choose concat or conj as the fn to apply to an existing sequential collection (not a seq) and a value, in which case ((if (sequential? v) concat conj) s v) is a pretty clean way to go. WDYT?

dvcrn07:11:40

Hey guys, I'm currently trying a project euler challenge in clojure and need to optimise for speed. Anyone able to help me out?

dvcrn07:11:54

Challenge is https://www.hackerrank.com/contests/projecteuler/challenges/euler117 My code is only able to pass the first testcase and times out at the other ones. It needs to execute under 8s and either the testdata is wrong (could be! it errored with RuntimeError at my python solution) or my solution is just too slow

dvcrn07:11:58

(Though it passes the first one in 2s so it might really be the input data...)

danielcompton07:11:25

@dvcrn: usually the first data set is small, and then hackerrank blows the size up for the later tests

dvcrn07:11:14

makes me wonder if this is even solvable for 10^18 in under 8s. That stack is huge

dvcrn07:11:40

the original euler challenge only wants the result for 50

dvcrn07:11:20

In any way, here is my code. If someone has a thought, let me know.

(defn exp [x n]
  (reduce * (repeat n x)))

;; Using a vector here because of O(1) access time
(def possibilities-for-space (atom [0 1 2 4 8 15]))
(def tiles [1 2 3 4])
(def m (exp 10 18))

(defn calculate [length]
  (if (<= length 5)
    (@possibilities-for-space length)
    (do
      ;; Iterate through 6 -> n
      (doseq [l (range 6 (+ length 1))]
        (let [possibilities (atom 0)]
          ;; For each length, we need to match all possible tiles
          (doseq [tile tiles]
            (let [r (- l tile)]
              ;; If we have a rest between length and tile, add with saved subresult for r
              (if (>= r 0)
                (swap! possibilities #(+ % (@possibilities-for-space r))))))
          ;; The vector is linear so we can just append.
          (swap! possibilities-for-space #(conj % (mod @possibilities m)))))
      ;; Return last element
      (@possibilities-for-space length))))

(calculate (bigint (exp 10 18)))

sarcilav07:11:55

mmm, what about a different approach, trying to build each new length using the previous ones, something like: you know that for each 2 black that are together you can replace it for a red one, and so on, leading to just computing the replacements and multiplying by the permutations

sarcilav07:11:37

so at the end for example with just red and black tiles for example you build the length 5 by using the different options for length 3 by adding a red one at the end, plus the options of the length 4 by adding the black one at the end

dvcrn07:11:08

I'm doing something similar above. I calculate all the permutations for each value. Once we have that, it is solvable very easy with dynamic programming. E.g. length = 5 5 - 1 (black tile) = 4. We already know that for a space 4, we have 8 permutations 5 - 2 (red) = 3 = 4 permutations 5 -3 (green) = 2 = 2 permutations 5 - 4 (blue) = 1 = 1 permutation = 8 + 4 + 2 + 1 = 15

dvcrn07:11:28

but I think that is way too slow

sarcilav07:11:54

and are you only keeping those 5/4 lvls at all times?

sarcilav07:11:24

(I’m typing from bed, 3am here, so it is not that easy to follow your code)

dvcrn07:11:38

I am keeping all 1..n

sarcilav07:11:50

maybe that it is a little optimization that you are missing

sarcilav07:11:26

once you are at K, you won’t need values like K-5, K-6, … and so on

dvcrn07:11:48

though vectors have O(1) access time. Besides space, I am not sure if it will impact on speed so much

sarcilav07:11:53

not sure either, but maybe you save some stack/creation time, (I’m going to bed, will check in the morning again, good luck)

dvcrn08:11:31

I think the solution is a math formula that we have to calculate that we can just apply to any number

dvcrn08:11:59

even with more math based approaches, doing it under 8s is still not possible. :confused:

thheller08:11:45

@dvcrn: try using loop instead of doseq/atom

thheller08:11:55

loop is a lot faster

thheller08:11:59

or try using volatile! vswap! instead of atom

thheller08:11:23

atom does CAS and since you do not use thread the compare doesn't do anything useful

dvcrn08:11:49

let me try that. But even with this, i think the approach above is just not fast enough by itself to ever handle 10^18

dvcrn08:11:22

10^8 is already wayyy to slow

thheller08:11:24

I haven't checked what you are trying to do

thheller08:11:38

just saw how you are doing it

thheller08:11:46

and doseq + atom is bad

dvcrn08:11:46

please feel free to give it a spin :simple_smile:

thheller08:11:50

loop is what you want

thheller08:11:18

but and "easy" optimization is switching from atom to volatile!

thheller08:11:18

but if you want better performance you'd need to rewrite everything to loop+`recur`

thheller08:11:47

or if you want to get crazy use a mutable array :wink:

dvcrn08:11:23

@thheller: do you know the actual speed difference between loop v doseq?

dvcrn08:11:27

out of curiousity

thheller08:11:57

it is more about the removal of swap! not so much about loop vs doseq

thheller08:11:49

loop and doseq are about equal, but loop has a return value :wink:

mpenet08:11:50

doseq does chunking/(seq...), also loop prolly allows you to throw away the atom and just use a local var

mpenet08:11:32

(loop [possibilities 0 ...] ...) etc

thheller08:11:35

yes, local binding in loop. removing the global atom is the important part

dvcrn08:11:07

interesting

mpenet08:11:03

I'd say start here and then profile... otherwise it's just going to be guesswork

thheller08:11:45

I'd be curious what volatile! buys you .. but in the end you'll need loop

mpenet08:11:14

not much imo, I really doubt the atom is the bottleneck

thheller08:11:32

in such a tight loop it should actually be quite a lot

thheller08:11:55

but not enough :simple_smile:

thheller08:11:26

well quite a lot is probably incorrect

mpenet08:11:38

prolly even more, but avoiding a volatile even would be nice anyway

mpenet08:11:07

I could be wrong, but I guess it would make hotspot work easier

thheller08:11:30

hmm interesting

thheller08:11:33

doesn't do anything :simple_smile:

thheller08:11:00

volatile is about equal to atom

dvcrn08:11:35

well feel free to tinker around. I for my part can't optimise it more. Just by the nature on it, doing 10^18 in under 8s (minus probably 2s clojure startup time) with loops seems to be close to impossible

thheller08:11:37

10^7 already runs out of memory :simple_smile:

dvcrn08:11:12

yeah we should probably clean up values we don't need anymore

thheller08:11:15

@dvcrn: try writing it with loop+`recur` ... you will see substantial improvements

denis08:11:25

Hi! A question, maybe not technical, but rather about learning organization. What are the good ways to learn Clojure through participating in the projects? Of course, there is a such thing as a pull request in github. But maybe there exist richer environments around some projects, with discussions, planning and accessible for those who just start learning Clojure?

pupeno09:11:14

To test my library jar-copier I need the name of jars than I can expect to be present in a standard java installation, in the classpath. Does anybody know of any?

adebesin09:11:30

@denis: I learned Clojure here http://www.codewars.com/ and here https://tbaldridge.pivotshare.com/ after you get to a point where you feel your competent enough.. look at starting your own project. This could be a piece of software or maybe think about writing a book as a means of you learning more, whilst also teaching others.. try here: https://leanpub.com/ Its totally up to you, its just a case of doing the work.

dvcrn10:11:39

@denik: also check hackerrank and friends. They usually allow you to implement a solution in clojure as well. I personally learned clojure by just picking up a private project I wanted to do and do it in clojure instead

pupeno10:11:58

Why isn’t my mocked function being called in this example:

pupeno10:11:59

(with-redefs-fn {#'leiningen.core.main/warn (fn [& args] (println "Mocked"))}
    (leiningen.core.main/warn "foo”))

joseph10:11:06

according to this page: https://clojuredocs.org/clojure.core/with-redefs-fn, I guess you missed the # sign in the second line

joseph10:11:32

(with-redefs-fn {#'f (fn [] true)} #(println (f)))

pupeno10:11:10

Ah… it gets a function, not an expression. That seems odd.

dm310:11:49

(with-redefs [x/y (fn [& args])] ...)

bronsa10:11:30

@pupeno: with-redefs-fn is a function, with-redefs is a macro

bronsa10:11:58

with-redefs takes an expression, with-redefs-fn can't take an expression since it's a function, so it takes a thunk

pupeno10:11:01

Ah, -fn is about what it is, not what it acts on. Of course, functions are no different than any other var.

bronsa10:11:18

correct. it is not uncommon in clojure to have both a operation macro that takes an expression and a operation-fn fn that takes a thunk

bronsa10:11:09

this is really handy for the 5% of times when you need to construct the binding map at runtime

jaen12:11:44

Anyone ever encountered java.lang.RuntimeException: No such var: cljs.core.match/backtrack, compiling when using core.match?

joseph14:11:34

hmm..then @bronsa why is there both with-redefs and with-redefs-fn, since it seems they have the same functionality...

bronsa14:11:48

one is a macro and the other a function

bronsa14:11:02

the macro is usually ok and has easier "syntax"

bronsa14:11:11

but sometimes you don't know at compile time which vars you are going to redef

bronsa14:11:16

and you can only do that with the fn

dvcrn14:11:55

so the problem / puzzle I posted above is not solvable with DP. The numbers are just too big no matter how I would optimize it

dvcrn14:11:06

if anyone actually followed that :stuck_out_tongue:

dvcrn14:11:11

we need something in O(n) or O(log n)

joseph14:11:04

@bronsa: u r right, thanks. But a little harder to imagine some example, can you give one?

isaac14:11:36

I think clojure should support hash-map unquote-splicing

moxaj14:11:01

@isaac isn't x just a symbol there?

dominicm14:11:11

@isaac: I've tried this before :stuck_out_tongue:

isaac15:11:11

(let [x (list 1 2 3)] {[email protected] 4})` this can work

isaac15:11:50

(let [x (list 1 2 3)] `{[email protected] 4})

moxaj15:11:18

@isaac well, `(hash-map [email protected]) is an option

isaac15:11:34

yes, I use this aways

isaac15:11:24

but `{[email protected]} more convenient

isaac15:11:32

@moxaj: there is a big difference is: {} is generate hash at compiler time, (hash-map …) at run time.

moxaj15:11:46

@isaac hey, that's new to me - thanks for mentioning!

roelof15:11:54

sorry to hijack this topic but what does [email protected] x ?

isaac15:11:54

so you can (let [{a :a} {:a 42}]), but can not (let [(array-map 'a :a) {:a 42}])

lvh17:11:56

Is there a way to get CIDER to use the :repl profile when doing cider-jack-in? http://blog.maio.cz/2015/11/cider-slows-down-leiningen-startup-here.html seems like a super useful hack, but it also breaks CIDER...

malch18:11:24

@lvh: works fine for me, just tried

maio19:11:43

@lvh: that should work without any modification (uhm at least it works on my machine). it just runs lein repl :headless which should use :repl profile.

birdspider20:11:37

<- emacs noob, day 3 of (spac)emacs - If I want the start (first few words) of the docstring during autocomplete or below the modeline next to the fn-signature, what is the term I should be googling for ? (autocomplete, fn-signatures and cider-doc are working)

iwillig21:11:32

is there a high order function in clojure that swaps the arguments so like (a-function a b) but allow you to call it with (a-function b a). I thought there was but for the life of me i can’t remember the name of it

borkdude21:11:20

someone mentioned 'binding.pry' for Clojure recently, but I lost the link and can't find it anymore

eraserhd21:11:33

@iwillig: There isn’t one. Using #(a-function %2 %1) is generally useful for this.

eraserhd21:11:43

There is one in Haskell.

eraserhd21:11:17

(It’s called flip)

eraserhd22:11:41

So here’s a really abstract, but small, clojure design question: What do you do when you are threading a value but you want to return more than just that value in a particular case? E.g. the threaded value and another piece of information? I’m not happy with any of the obvious options.

eraserhd22:11:18

I could throw an exception. This case is kind of like a failure case, but not exactly. But I don’t want to use exceptions for flow control.

eraserhd22:11:48

I could return [a b] where a is the threading value and b is the extra info, but this is kind of hard to work with for threading. and it makes the return value stick out like a sore thumb from the rest of the similar functions.

eraserhd22:11:07

I could return nil or a different type and check it higher up.

eraserhd22:11:39

I could stick some extra keys on the threaded value.

eraserhd22:11:23

Not gonna mutate.

seancorfield22:11:55

Break the threading flow in two at the condition point?

eraserhd22:11:40

As I was thinking about it, I figured I wanted a monad-like thing threading (a, Option b), and bind just doesn’t execute the operation if the second in the tuple is Just _. And then I realized that I’m reimplementing exceptions.

mrg22:11:18

Sounds exactly like on option monad to me :wink:

mrg22:11:42

There are a couple of implementations of those floating around.. maybe just take one and adjust as needed?

eraserhd22:11:56

@mrg My experience has been that monads are really noisy in clojure. Like, monads the type theory is useful in building things, but monads-as-lisp-syntax is usually painful. But I think I’ve solved my problem by using exceptions.

eraserhd22:11:15

(but thanks!)

mrg22:11:21

okay, perfect

mrg22:11:34

I thought that was really neat

eraserhd22:11:58

@mrg Oh wow, that is neat.

noonian22:11:47

I’d make the thing you thread a map containing the value e.g. {:a a, :b b} instead of the value itself and can annotate it with extra stuff if you need to without altering the threading code. I’d probably call it context.

johanatan23:11:11

@eraserhd: have you tried cats?

johanatan23:11:44

It doesn't look 'noisy' at all to me.

eraserhd23:11:14

@johanatan: Oh. I looked at that for another reason, not the syntax.

johanatan23:11:10

But it's probably the canonical way to do monady things in Clj no? @eraserhd