Fork me on GitHub
#beginners
<
2020-10-12
>
João Galrito03:10:25

let's say I have 3 threads that will modify some vec. The threads can add or change stuff in it. Whenever vec reaches a certain size, I want to do some side effects and reset it to be empty. I tried this with an atom to hold the vec and add-watch to fire the side effect and reset!, but it seems that the threads might see the atom in its old state after the side-effect is performed but before the atom is reset

alexmiller03:10:43

yeah, watchers are not synchronous to the change so that's not a viable option. really if you need to trigger side effects atoms aren't going to work. maybe an agent would be an option?

João Galrito03:10:29

so I do the side effect and reset the agent inside a send?

hiredman06:10:46

You could also use compare-and-set! on the atom instead of swap!

hiredman06:10:31

And if you successfully cas in the empty vector do the side effect

Chris K06:10:46

how can use clojure with clojurescript? I know I can just create files and stuff, but how would I create a lein project that uses both clojure and clojurescript

mavbozo06:10:04

create your clojure project with leiningen then use leiningen's plugins such as lein-cljsbuild, or figwheel for managing your clojurescript codes

Chris K06:10:44

can you give like an example? if possible? like lein new compojure hello-word and then?

mavbozo07:10:04

@sunchaesk you can use luminus template https://github.com/luminus-framework/luminus-template to create clojure & clojurescript based webapp in a leiningen project. lein new luminus my-project +cljs .

Jim Newton07:10:45

the function distinct will give me the sequence with duplication removed. How can I find the actual duplicates? Of course I can write a function to do this, but it seems there should be a sister-function to distinct

mavbozo07:10:41

can't recall whether sister-function to distinct exists, but maybe frequencies helps you get there

Jim Newton07:10:53

Currently I have just written a local function:

(find-duplicates [items]
              (loop [items items
                     duplicates []]
                (cond (empty? items)
                      (distinct duplicates)

                      (member (first items) (rest items))
                      (recur (rest items)
                             (conj duplicates (first items)))

                      :else
                      (recur (rest items)
                             duplicates))))

Jim Newton07:10:30

I'm not really concerned about performance as this code is only called in an error message. However, if there's a simple way to do it the code will of course be more understandable when I look at it again in a few months.

Jim Newton07:10:22

BTW, member is defined elsewhere as

(defn member
  "Like cl:member.  Determines whether the given target is an element of the given sequence."
  [target items]
  (boolean (cond
             (nil? target) (some nil? items)
             (false? target) (some false? items)
             :else (some #{target} items))))

mavbozo08:10:40

i use frequencies to get the duplicates like this

(->> (frequencies [1 2 3 1 3 4 3 2])
     (remove (fn [[k v]] (= 1 v)))
     (map (fn [[k v]] k)))
;; ;; => (1 2 3)

Jim Newton09:10:22

is that the same as?

(->> (frequencies [1 2 3 1 3 4 3 2])
     (remove (fn [[k v]] (= 1 v)))
     (map first))

Darin Douglass10:10:57

Yes, which is the same as:

(->> (frequencies [1 2 3 1 3 4 3 2])
     (remove (comp #(= 1 %) val))
     (keys))

Jim Newton12:10:32

Am I the only one who believes that that snippet does not express the intent: find-duplicates ??

Jim Newton12:10:25

somewhat reminiscent of Perl coding from the 1990s.

( ($h{$_}++ == 1) || 0)
($l=join("",<>))=~s/.*\n/index($`,$&)>=$[||print$&/ge;

Darin Douglass12:10:07

IMO that snippet reads fine to me unlike that perl code :P

🙂 3
Darin Douglass12:10:28

I go back to perl whenever my company has code golfing tournaments

🙂 3
alexmiller12:10:39

I’d use group-by

alexmiller12:10:11

With identity

Jim Newton11:10:41

yes group-by probably does have n log(n) complexity while my recursive approach has n^2 complexity

Jim Newton11:10:09

converting n^2 to n log(n) is worth making the code less readable.

borkdude10:10:50

@jimka.issy

(partition-by identity [1 2 2 2 3 4 4 1 1 1])
((1) (2 2 2) (3) (4 4) (1 1 1))

borkdude10:10:01

if the succession is important - I think this is more like an alternative approach to dedupe

✔️ 3
Jim Newton12:10:08

the function apparently accepts a string, naming a file, and attempts to delete the file. Is there such a function while will tell me whether the file exists? I'm not so gifted in interfaces into the mysterious java world.

delaguardo12:10:45

(defn exists? [f]
  (.exists ( f)))

3
dpsutton15:10:00

this seems like spam, especially for the beginners channel

3
🙏 3
Michael Stokley16:10:34

mapping over the same collection multiple times can be space-inefficent, right? for example (->> xs (map f1) (map f2)). if so, is sequence a solution? eg (sequence (comp f1 f2) xs)

dpsutton16:10:23

(map (comp f2 f1) xs) should work as well

Michael Stokley16:10:08

oh, that's great news. thank you!

Steven Katz16:10:49

also (comp (map f1) (map f2))

Michael Stokley16:10:03

i'm not sure this works the way you might expect

Michael Stokley16:10:50

because (map f1) doesn't return a function that takes a collection, applies f1 to every element

Michael Stokley16:10:56

it returns a transducer (i think)

Michael Stokley16:10:41

((comp (map inc) (map dec)) [1 2 3])
;; => #function[clojure.core/map/fn--5847/fn--5848]

Michael Stokley16:10:20

in other functional languages, i would expect (map f1) to essentially do partial application.

Steven Katz16:10:20

I think I meant (map (comp (map f1) (map f2)) xs)…that is you can compose the transducers, which is suppose to be more efficient then ->> solutions.

Michael Stokley16:10:04

(map (comp (map inc) (map dec)) [1 2 3])
;; => (#function[clojure.core/map/fn--5847/fn--5848]
;;     #function[clojure.core/map/fn--5847/fn--5848]
;;     #function[clojure.core/map/fn--5847/fn--5848])
???

Steven Katz16:10:44

I’m messing up the correct way to compose and use transducers…let me look into it

Michael Stokley16:10:13

it's really counter-intuitive! IMO

Steven Katz16:10:33

(def xf (comp (map inc) (map inc)))
(into [] xf (range 1000))

Steven Katz16:10:52

My understanding is that there is no intermediate collection created between the maps, so its as memory efficient as possible

🙌 3
Steven Katz16:10:15

also look into the “transduce” function

Michael Stokley16:10:50

how do you understand the difference between into and sequence? sequence is lazy?

noisesmith16:10:59

sequence is lazy, yes

Michael Stokley16:10:42

so if i expect the entire transformed collection to be consumed, sequence may be overkill? and i should favor into?

noisesmith16:10:32

usually transducers are used in situations where you want to avoid laziness, so in practice sequence is very rarely used

noisesmith16:10:05

I'd start with your use case - do you need indexed lookup? do you need fast membership testing?

noisesmith16:10:19

and pick the data structure that performs best for your usage

Michael Stokley16:10:42

i don't need those things, no. all i want to do is apply a series of maps and mapcats over a vector to create a new vector. normally i'd use (->> xs (map f) (mapcat g)) and not worry about the inefficiency

Michael Stokley16:10:18

i'm not sure i quite follow why the data structure question is relevant? can you put it another way?

noisesmith16:10:04

that mapcat won't return a vector

noisesmith16:10:51

the first question is what data structure you need, if all that matters is that the result be ordered (lazy seq or vector) then you can look at secondary concerns

noisesmith16:10:02

and finally efficiency may or may not be a concern

Michael Stokley16:10:03

... on reflection, i don't need my results to be ordered. and duplicate elements in the collection aren't meaningful to me. i was using the term vector carelessly.

noisesmith16:10:33

in that case you might want (into #{} ...)

noisesmith16:10:47

what are you doing with the resulting collection?

Michael Stokley17:10:23

... i'll use it to test membership - like i said i didn't need. if an element in present in the resulting collection, that will influence how i handle another set of values.

practicalli-john18:10:36

If I have the following data set, how to I get the totals for each country in a map with each countries total (without writing a loop-recur preferably)

[{:date "10-10-2020" :england 3665 :scotland 821 :wales 56 :northern-ireland 821}
   {:date "09-10-2020" :england 5593 :scotland 833 :wales 194 :northern-ireland 888}
   {:date "08-10-2020" :england 11601 :scotland 845 :wales 486 :northern-ireland 1029}
   {:date "07-10-2020" :england 13871 :scotland 1019 :wales 724 :northern-ireland 1087}
   {:date "06-10-2020" :england 13997 :scotland 1195 :wales 708 :northern-ireland 846}
   ,,,
   ]
So the output wold look likke {:england 43343 :scotland 44343 :wales 3232 :northern-ireland 343}

teodorlu18:10:27

Huh, so you actually have 4 data points per row

teodorlu18:10:52

And the date field "doesn't count"

rakyi18:10:59

dissoc :date and merge-with +

👍 3
practicalli-john18:10:55

@rakyi ah, this seems to work (apply merge-with + (map #(dissoc % :date ) data)) Is that what you meant? data is the data set above

rakyi18:10:15

I thought you’d easily figure it out given the hints 🙂

👍 3
teodorlu18:10:34

A more long-winded approach, based on a whitelist.

practicalli-john18:10:32

I love this solution purely for the number of core functions you manage to use together :)

😅 3
😄 3
sova-soars-the-sora18:10:28

Anybody make any apps for android via cljs?

practicalli-john18:10:22

React Native and ClojureScript seems to be the most common approach... That way you also should get other mobile devices supported too..

practicalli-john18:10:35

Take a look at these resources...https://cljsrn.org/

practicalli-john18:10:26

There is also a #react-native and #clojure-android channels in case your request gets lost in the general beginners channel

sova-soars-the-sora18:10:15

I want to make a "native app" using CLJS... wondering if I can use any react-ish library and package it somehow ?

noisesmith19:10:59

react-native was once the choice for that, might still be

3
Frederik19:10:24

Hi! I'm implementing a negamax search (https://en.wikipedia.org/wiki/Negamax ) to use in combination some reinforcement learning. I just brute-forced it with a recursive function, but was wondering if people could give some feedback on obvious ways to improve it. Speed is my main concern, but happy to learn about anything that is an anti-pattern/not clojure-onic also:

(defn negamax
  [q-values game-state depth]
  (cond
    (pol/finished-game? game-state) (pol/reward game-state)
    (= depth 0) (pol/get-value q-values game-state)
    :else (let [actions (pol/get-available-actions game-state)
                depth (dec depth)]
            (apply 
             max
             (map
              (fn [action]
                (- (negamax q-values
                             (pol/apply-action game-state action)
                             depth)))
              actions))))) 
q-values is a neural-net, game-state the position in the game (in tictactoe e.g.) Not core to the function I think, but finished-game?, reward, apply-action and get-available actions are methods of a protocol:
(defprotocol GameState
  (finished-game? [this] "Tests if game is finished")
  (reward [this] "Gives reward for state")
  (get-available-actions [this] "Gives all available actions from this state")
  (apply-action [this action] "creates new state through action"))
Hope I'm posting this in the right place! 🙂

thom20:10:19

So the first thing to consider is whether some sort of alpha/beta cutoff would work for you. That can hugely reduce the search space.

thom20:10:45

I also assume you can memoise some of the GameState functions (in chess engines you build transposition tables because different sequences of actions can lead to the same position)

thom20:10:58

In terms of Clojure stuff, you could look at parallelising stuff a bit more. Given that you’re just exhaustively searching to a certain depth this should work well.

Frederik21:10:45

Thanks! alpha/beta was going to be my next step, but thought asking this with the basic negamax was clearer. Are there any clojure related changes that could help? I've never used type hinting for example, useful here?

Frederik21:10:46

parallelising seems like a good idea indeed! A very naive memoising the whole function didn't seem to help (not sure why, the inputs being too complex?), but something to try to improve