beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
João Galrito 2020-10-12T03:34:25.179900Z

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

alexmiller 2020-10-12T03:46:43.180900Z

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 Galrito 2020-10-12T03:52:29.181700Z

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

2020-10-12T06:02:46.182700Z

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

2020-10-12T06:03:31.183700Z

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

Chris K 2020-10-12T06:26:46.184400Z

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

mavbozo 2020-10-12T06:39:04.185500Z

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

Chris K 2020-10-12T06:40:44.186500Z

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

Chris K 2020-10-12T06:44:23.186800Z

@mavbozo forgot to tag

mavbozo 2020-10-12T07:03:04.188200Z

@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 Newton 2020-10-12T07:14:45.189600Z

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

mavbozo 2020-10-12T07:17:41.191200Z

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

Jim Newton 2020-10-13T11:15:41.270500Z

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

Jim Newton 2020-10-13T11:16:09.270700Z

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

Jim Newton 2020-10-12T07:44:53.191300Z

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 Newton 2020-10-12T07:45:30.191500Z

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 Newton 2020-10-12T07:48:22.191700Z

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))))

mavbozo 2020-10-12T08:23:40.192Z

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 Newton 2020-10-12T09:57:22.192500Z

is that the same as?

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

borkdude 2020-10-12T10:06:50.193200Z

@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))

borkdude 2020-10-12T10:08:01.193800Z

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

✔️ 1
Darin Douglass 2020-10-12T10:58:57.197400Z

Yes, which is the same as:

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

Jim Newton 2020-10-12T12:15:08.200Z

the function <http://clojure.java.io/delete-file|clojure.java.io/delete-file> 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.

Jim Newton 2020-10-12T12:16:32.200200Z

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

Jim Newton 2020-10-12T12:18:25.200400Z

somewhat reminiscent of Perl coding from the 1990s.

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

2020-10-12T12:18:45.200600Z

(defn exists? [f]
  (.exists (<http://clojure.java.io/file|clojure.java.io/file> f)))

1
Darin Douglass 2020-10-12T12:33:07.203Z

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

🙂 1
Darin Douglass 2020-10-12T12:33:28.203800Z

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

🙂 1
alexmiller 2020-10-12T12:37:39.204600Z

I’d use group-by

alexmiller 2020-10-12T12:38:11.205100Z

With identity

dpsutton 2020-10-12T15:54:00.206300Z

this seems like spam, especially for the beginners channel

➕ 1
🙏 1
2020-10-12T16:05:34.208300Z

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

dpsutton 2020-10-12T16:08:23.208900Z

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

2020-10-12T16:11:08.209500Z

oh, that's great news. thank you!

Steven Katz 2020-10-12T16:13:49.210800Z

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

2020-10-12T16:21:03.210900Z

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

2020-10-12T16:21:50.211100Z

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

2020-10-12T16:21:56.211300Z

it returns a transducer (i think)

2020-10-12T16:22:41.211500Z

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

2020-10-12T16:24:20.211700Z

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

Steven Katz 2020-10-12T16:26:20.211900Z

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.

2020-10-12T16:27:04.212100Z

(map (comp (map inc) (map dec)) [1 2 3])
;; =&gt; (#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 Katz 2020-10-12T16:27:44.212300Z

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

2020-10-12T16:28:13.212500Z

it's really counter-intuitive! IMO

Steven Katz 2020-10-12T16:34:33.212700Z

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

Steven Katz 2020-10-12T16:35:52.212900Z

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

🙌 1
Steven Katz 2020-10-12T16:36:15.213100Z

also look into the “transduce” function

Steven Katz 2020-10-12T16:37:04.213300Z

https://clojure.org/reference/transducers

2020-10-12T16:39:50.213600Z

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

2020-10-12T16:41:59.213800Z

sequence is lazy, yes

2020-10-12T16:43:42.214Z

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

2020-10-12T16:44:32.214200Z

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

2020-10-12T16:45:05.214400Z

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

2020-10-12T16:45:19.214600Z

and pick the data structure that performs best for your usage

2020-10-12T16:46:42.214800Z

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 (-&gt;&gt; xs (map f) (mapcat g)) and not worry about the inefficiency

2020-10-12T16:47:18.215Z

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

2020-10-12T16:53:04.215200Z

that mapcat won't return a vector

2020-10-12T16:53:51.215400Z

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

2020-10-12T16:54:02.215600Z

and finally efficiency may or may not be a concern

2020-10-12T16:57:03.215800Z

... 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.

2020-10-12T16:57:33.216Z

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

2020-10-12T16:57:47.216200Z

what are you doing with the resulting collection?

2020-10-12T17:00:23.216500Z

... 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.

2020-10-12T17:11:25.216800Z

thank you @noisesmith and @steven.katz

2020-10-12T17:11:27.217Z

!

practicalli-john 2020-10-12T18:00:36.219400Z

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}

teodorlu 2020-10-12T18:02:27.220400Z

Huh, so you actually have 4 data points per row

teodorlu 2020-10-12T18:02:52.221100Z

And the date field "doesn't count"

teodorlu 2020-10-12T18:02:53.221400Z

?

rakyi 2020-10-12T18:02:59.221500Z

dissoc :date and merge-with +

👍 1
teodorlu 2020-10-12T18:03:19.221800Z

Smart

rickheere 2020-10-12T18:03:41.222Z

hcl in lt

practicalli-john 2020-10-12T18:09:55.223200Z

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

rakyi 2020-10-12T18:12:17.223700Z

yes

rakyi 2020-10-12T18:13:15.224600Z

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

👍 1
teodorlu 2020-10-12T18:13:34.224700Z

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

sova-soars-the-sora 2020-10-12T18:39:28.226700Z

Anybody make any apps for android via cljs?

practicalli-john 2020-10-12T18:39:32.226800Z

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

😄 1
😅 1
sova-soars-the-sora 2020-10-12T18:40:15.227400Z

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

practicalli-john 2020-10-12T18:40:22.227500Z

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

practicalli-john 2020-10-12T18:41:35.227700Z

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

practicalli-john 2020-10-12T18:43:26.227900Z

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

2020-10-12T19:42:59.228800Z

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

1
Frederik 2020-10-12T19:55:24.233800Z

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! 🙂

thom 2020-10-12T20:18:19.234800Z

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.

thom 2020-10-12T20:20:45.236600Z

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)

thom 2020-10-12T20:29:58.239200Z

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.

Frederik 2020-10-12T21:49:45.239800Z

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?

Frederik 2020-10-12T21:50:46.240Z

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

thom 2020-10-12T22:16:39.241200Z

Type hints definitely can help, have a look at https://clojuredocs.org/clojure.core/warn-on-reflectionhttps://clojuredocs.org/clojure.core/warn-on-reflection. Also worth turning on warnings for boxed math(s): https://insideclojure.org/2014/12/15/warn-on-boxed/