Fork me on GitHub
#clojure
<
2017-12-17
>
tbaldridge01:12:31

@xiongtx It's mostly to stop you from shooting yourself in the foot. There's some strange cases where you could cause cross-thread mutation with set! and bindings. I don' have a REPL infront of me at the moment, but I think this would cause the error:

(def ^:dynamic myval nil)

(binding [myval 32]
  (set! myval 42)
  (future (set! myval 45)))

tbaldridge01:12:55

So that's the gist of it, we bound a dynamic var, set! a value locally, then tried to set it again in another thread. I think that will cause an error and that error occurs when you set an already set val from a different thread than the first set!. The thread that set the value is tracked in TBox.

xiongtx01:12:51

I see, so it's to handle binding conveyance? B/c AFAICT that's the only way frames are shared b/t threads. Relevant code: https://github.com/clojure/clojure/blob/clojure-1.9.0/src/jvm/clojure/lang/Var.java#L219

xiongtx02:12:33

But I'm actually not sure why the two set!s is a problem? Each thread gets its own frames, so they won't interfere w/ each other.

tbaldridge01:12:51

Using TBox also improves performance a bit, since set! is then allocation free. Without TBox you'd have to do an assoc into the contents of the current Frame, and that would require an allocation.

qqq05:12:54

Does anyone else here see a need for something like: https://github.com/aaronc/c-in-clj but targetting both webassembly (to be called from cljs) and cuda (to be calledc from clojure/jcuda)? I want to write high performance numerical code in something that is clojure-like, and be able to invoke it directly from clojure

qqq07:12:14

Is there a way, either using transient! vector or a native java array, to get CONSTANT TIME, not log_32 N time for following op: set n-th element of array/vector/object to :foo

tbaldridge14:12:03

sure, aset on an object array is constant time. At least as constant as system memory allows (nothing is really constant time in modern hardware).

matan10:12:40

@seancorfield oh is it already available as an e-book?

seancorfield04:12:06

Full TOC, some free downloadable chapters/excerpts, Beta e-book. I buy most of my tech books in Beta/Early Access direct from the publishers these days.

matan10:12:38

I wish there was a TOC of it to look at, but on Amazon there’s none yet

qqq11:12:52

what is this? are you live casting using a library to control a web browser via clojure ?

qqq11:12:18

(it's almost 5am here, I'm trying to decide to sleep or to wait)

ihabunek12:12:09

hi! I'm having trouble with recursion when a function recurs multiple times per call, e.g. when mapping itself over some list I don't know how to avoid blowing the stack for larger inputs here's a (over)simplified example, a function which counts the nodes in a tree: https://gist.github.com/ihabunek/927e8534bef011dd9c14f0284153e678 AFAIK, loop/recur is not viable here any hints would be appreciated.

qqq12:12:05

@igrishaev: how do we join the chat ?

hmaurer12:12:49

@ihabunek you can definitely use loop/recur here, but I think you will need an accumulator parameter

ihabunek12:12:35

ok, i'll give it a shot

hmaurer12:12:59

it will be less sexy than the way you expressed it with recursion though…

hmaurer12:12:11

as in, it will be less explicit as to what it is doing

hmaurer12:12:24

but it should get rid of the stack overflow problem if you do it properly

ihabunek12:12:39

the actual problem is navigating a branching maze, which is similar to the example

hmaurer12:12:01

what about using a stack?

hmaurer12:12:11

use two exta parameters, an accumulator (integer accumulating the count)

hmaurer12:12:16

and a stack of things left to explore

hmaurer12:12:31

basically modelling a breadth first / depth first traversal

hmaurer12:12:39

there might be std lib functions for that actually, not sure…

ihabunek12:12:01

not too experienced with B/DFS, will need to explore it a bit before i can answer your question

hmaurer12:12:03

so you could start with an accumulator of 0 and a stack containing only the first node you need to explore

ihabunek12:12:28

stack would contain the ones i have left to explore?

ihabunek12:12:49

as opposed to the ones i have already explored

hmaurer12:12:57

yeah, left to explore

hmaurer12:12:10

actually, instead of having an accumulator with th count, you could also just flatten the tree to a list

hmaurer12:12:19

then count the numbr of elements in that list

hmaurer12:12:29

hang on, I’ll write you an example

ihabunek12:12:30

ok, the tree is a stupid example 🙂

ihabunek12:12:01

the stack of things left to explore sounds good for this tree problem, and for mazes which don't have loops

ihabunek12:12:13

if i have loops i guess i'd have to store places already visited

hmaurer12:12:13

yep, if you have loops it’s different 😞

hmaurer12:12:40

there might be more optimized algorithms then though, I am not familiar with graph traversal algos

hmaurer12:12:05

if you were really worried about performance I am sure optimized versions exist

hmaurer12:12:05

but I think the basic answer to what you were asking is: “use an extra helper function with an ‘accumulator’ parameter, then use recur/loop”

ihabunek12:12:55

i'm looking at the actual problem i had 😄

ihabunek12:12:00

trying to apply it

hmaurer12:12:10

but personally I would still use the recursive approach (with stack overflow issues fo large inputs) if I know my inputs will be small

hmaurer12:12:16

because it’s usually more expressive

hmaurer12:12:20

at least to me

ihabunek12:12:23

i like the recursion too

ihabunek12:12:38

i was under the impression that it's not possible to (map recur ...)

hmaurer12:12:55

yeah it’s not possible to do (map (recur directly

hmaurer12:12:36

hang on, I’m writing you an example 🙂

ihabunek12:12:37

here's my actual problem, i cleaned it up a bit https://github.com/ihabunek/aoc2016/blob/master/src/aoc2016/day17.clj#L53 this works well when the limit is under several hundred, but the second part of the assignemnt is to find the longest possible path and that's too much

ihabunek12:12:07

wow cool site

hmaurer12:12:35

for the longest possible path yo might want to take a different approach if the graph is big though

hmaurer12:12:34

and yes http://repl.it is cool 🙂

ihabunek12:12:56

interesting approach, thanks for that example

ihabunek12:12:03

reducing it with set/union, makes sense

hmaurer12:12:44

yeah; actually now that I think of it it’s unecessary if you have a tree structure

hmaurer12:12:52

since the same node will never appear twice

ihabunek12:12:02

so you have recur without loop, didn't know that was a thing

hmaurer12:12:08

but if you had a DAG (directed acyclic graph), then that approach would still work

hmaurer12:12:27

oh hang on

hmaurer12:12:34

no it wouldn’t it would overcount some nodes…

hmaurer12:12:46

yes you can recur on the whole function

hmaurer12:12:35

I think it the doc it says that recur “recurs to a recursion point”

hmaurer12:12:40

loop introduces a recursion point

hmaurer12:12:49

but the function itself is also a recursion point

ihabunek12:12:51

docs can sometimes be a bit terse

ihabunek12:12:57

makes sense

ihabunek12:12:10

http://clojuredocs.org is nice for examples though

hmaurer12:12:34

just for the record: I shouldn’t have used set in the example I gave you; at first sight it makes sense, but thinking a bit more about it it doesn’t seem to make sense at all

ihabunek12:12:00

i usually use a list to preserve order

hmaurer12:12:03

well, it makes some sense, but if you wanted it to behave well on DAGs the function would need to have extra logic to handle already visited nodes

ihabunek12:12:20

thanks, i think you've steered me in the right direction, i'll play around with it

bfay20:12:29

@ihabunek I was trying to do a DFS in clojure recently and had a similar problem; it didn't seem natural to recur in tail call position. I found an answer in Stuart Sierra's dependency library, it's a little bit terse but way more elegant than anything I came up with.

(defn- transitive
"Recursively expands the set of dependency relationships starting
at (get neighbors x), for each x in node-set"
[neighbors node-set]
(loop [unexpanded (mapcat neighbors node-set)
expanded #{}]
(if-let [[node & more] (seq unexpanded)]
(if (contains? expanded node)
(recur more expanded)
(recur (concat more (neighbors node))
(conj expanded node)))
expanded)))

ihabunek20:12:10

that's actually very neat

ihabunek20:12:39

i need to examine it a bit more closely to understand it fully

ihabunek20:12:02

thanks 🙂

ihabunek20:12:33

reminds me of some examples in the Little schemer

bfay21:12:02

Oh I need to get that book, was tempted recently because the MIT Press had a 40% off black friday sale

hmaurer12:12:30

good luck!

ihabunek12:12:09

next year maybe i'll try racket to get some proper TCO 😄

jcthalys13:12:43

Please, someone could help me with this:

(->> (iota/seq "war-and-peace-full-book.txt")
     (r/filter identity)
     (r/map (fn [line]
              (re-seq #"\w+" line)))
     (r/fold (fn 
               ([] 0)                                  
               ([a line]
                (+ a (count line))))))
I’m trying this to count words in a file with parallel, that’s Ok with small files but with big txt files. I’m having this problem: UnsupportedOperationException count not supported on this type: Long clojure.lang.RT.countFrom (RT.java:664)

igrishaev13:12:43

@qqq to join the chat, you need to be logged on Youtube using your google account.

noisesmith16:12:34

@jcthalys r/fold takes an optional combining function which combines the results of multiple folds; your fold returns a number, if the combine function is not provided, it tries to use your reduce function

noisesmith16:12:12

@jcthalys I think you can just tell it that your combine function is + so change (r/fold (fn ...)) into (r/fold + (fn ...)) and that should solve it

noisesmith16:12:24

@jcthalys to be totally clear - it's trying to pass a number to your function because you told it that function could be used to combine the result of multiple folds

noisesmith16:12:55

also, when you fix it by adding + as an arg, your function no longer needs a 0 arity to be defined - only the combining function is called with 0 args

rampal18:12:55

Hi, Is the Untangled Framework alive or abandoned?

qqq18:12:54

Is there a way to create an 'array' such that: 1. I can use aset on it 2. it works in cljc (i.e. both clojure and cljs) 3. it lets me store arbitrary object (i.e. not just float or int) I'm basically looking for 'array of references' Pre-emptive: why aren't you using a transient! vector? I want real O(1) aset, not O(log_32 n) assoc.

noisesmith18:12:15

#?(:clj (make-array Object 100) :cljs (make-array js/Object 100))

bronsa18:12:26

object-array

noisesmith18:12:50

oh, that's portable, nice

qqq18:12:34

nice; thanks!

zignd21:12:35

in plumatic/schema, is there an option that would allow you to create a condition for a value based on its key in a map? from my understanding it seems that s/conditional can only validate the value in which its placed

zignd21:12:52

consider

[{:something1 {:foo 1 :bar 2}}
 {:something2 {:span "2" :potato "3"}}]
then if the key is :something1 i'd like to use a certain schema to validate {:foo 1 :bar 2} but if the key is :something2 i'd like to use another schema to validate {:span "2" :potato "3"}.

noisesmith22:12:54

you can make an s/conditional that looks into the keys

noisesmith22:12:35

that is, a conditional that says apply schema1 if :something1 is present, otherwise schema2 if :something2 is present, otherwise some default

noisesmith22:12:50

then schema1 and schema2 have the apropriate maps under those keys

gklijs22:12:55

You could also use keys with or, something like (s/keys :req-un [(or :something1 :something2)])

zignd22:12:58

thanks guys, i ended up using @noisesmith's tip cuz i'm in a rush here

zignd23:12:19

@gklijs is there a keys function in schema? i couldn't find in the docs for the core namespace

noisesmith23:12:20

I think @gklijs was thinking of spec