beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
gibi 2020-12-28T00:00:22.058300Z

Hi, I’m sure I am using for in the wrong way, but out of curiosity, is there a function to turn a nested list such as (([[#{...} #{}] [#{...} #{...}]])) into something like [[#{...} #{}] [#{...} #{...}]] ? the function flatten gives a different result. Thanks

euccastro 2020-12-28T00:06:16.058900Z

ffirst ?

euccastro 2020-12-28T00:09:58.060100Z

that would work for your particular example. I don't know whether you have a more general pattern in mind. if so, please give an example where ffirst wouldn't work

gibi 2020-12-28T00:18:23.063Z

ffirst seems to work, thanks @euccastro πŸ‘

1πŸ‘
FHE 2020-12-28T03:00:32.063400Z

@seancorfield Yes, I just don't understand how to get there from the main Zulip clojurians screen.

Michael W 2020-12-28T03:55:07.065500Z

If I want to curry a function with 2 arguments, supplying the second argument, partial won't work. Is there anything that allows partial application of out-of-order arguments?

seancorfield 2020-12-28T04:21:25.066900Z

@michael819 That's what anonymous functions are for. And Rich Hickey says they are more idiomatic than partial anyway. #(f % 42) for a literal of f with the second argument provided.

Michael W 2020-12-28T05:05:08.067300Z

@seancorfield Thanks.

popeye 2020-12-28T06:57:36.068500Z

The difference between and @ is , is used to unquote variables and @ used for collections, Is my understanding correct?

2020-12-28T16:31:47.106200Z

@kumarshantanu the only difference between ~(+ x y) and (+ ~x ~y) is when the + call happens (during list building, or later when the compiled object is run) - the same variables are added in both cases (but they might have different values later)

Shantanu Kumar 2020-12-28T06:58:44.068600Z

You could also use ~ for whole expressions, as long as it’s just one expression.

popeye 2020-12-28T06:59:36.068800Z

ok, But my above understanding is correct?

Shantanu Kumar 2020-12-28T06:59:56.069Z

Yes

popeye 2020-12-28T07:00:58.069200Z

Thanks, can you give example for expression? is that ~(+ x y)

euccastro 2020-12-28T07:01:20.069400Z

inserts a single thing (possibly a collection too!) and @ splices a collection

euccastro 2020-12-28T07:02:21.069600Z

see

user=> (def a [:a :b :c])
#'user/a
user=> `(1 2 3 ~a 4 5)
(1 2 3 [:a :b :c] 4 5)
user=> `(1 2 3 ~@a 4 5)
(1 2 3 :a :b :c 4 5)

3
Shantanu Kumar 2020-12-28T07:02:23.069800Z

@popeyepwr Yes, ~(+ x y) is a correct example (assuming x and y resolve).

euccastro 2020-12-28T07:03:17.070100Z

here a is a variable and it evaluates to a collection

popeye 2020-12-28T07:04:48.070500Z

@kumarshantanu both (+ x y) and (+'x 'y) gave error after assigning x and 7 as 5 and 7

Shantanu Kumar 2020-12-28T07:06:29.070700Z

@popeyepwr When you use ~(+ x y) in a macro, x and y should be resolvable at compile time. To make it resolve at runtime, you need to use (+ ~x ~y).

euccastro 2020-12-28T07:06:30.070900Z

can you paste the whole expression? ~ is supposed to be used within a quasiquoted (i.e., preceded by a backtick) expression

popeye 2020-12-28T07:07:53.071100Z

@euccastro @kumarshantanu, That helped, Thanks πŸ™‚

euccastro 2020-12-28T07:09:14.071500Z

user=> (def x 5)
#'user/x
user=> (def y 7)
#'user/y
user=> `(:a :b :c ~(+ x y) :d)
(:a :b :c 12 :d)
user=> `(:a :b :c ~(+ 'x 'y) :d)
Execution error (ClassCastException) at user/eval1 (REPL:1).
class clojure.lang.Symbol cannot be cast to class java.lang.Number (clojure.lang.Symbol is in unnamed module of loader 'app'; java.lang.Number is in module java.base of loader 'bootstrap')

euccastro 2020-12-28T07:09:34.071700Z

the second case is an error because you are trying to add two symbols

euccastro 2020-12-28T07:09:57.071900Z

` suppresses evaluation, ~ reenables it

euccastro 2020-12-28T07:11:55.072200Z

you'd get the same error if you just tried to evaluate (+ 'x 'y), without using backquote or ~ at all

1πŸ‘
Christian 2020-12-28T11:07:03.076200Z

Hey there, I have some endless seqs of natural numbers, and I want to find the lowest number that is in all seqs. I'm not sure how to do it in a smart way. I could iterate through all natural numbers and check if it checks true for all the generation rules, but the final number is huge, so this will take a really long time. I'm sure there is a number-theory trick as well, but my residue system knowledge is not that good.

(def x0 (iterate #(+ 7 %) 7))
(def x1 (iterate #(+ 13 %) (+ 13 1)))
(def x2 (iterate #(+ 59 %) (+ 59 4)))
(def x3 (iterate #(+ 31 %) (+ 31 6)))
(def x4 (iterate #(+ 19 %) (+ 19 7)))

furiel 2021-01-06T11:53:29.270300Z

You could try the Chinese remainder theorem: https://en.wikipedia.org/wiki/Chinese_remainder_theorem If you scroll down to Existence (direct construction) , you can use that formula. You need to find or implement an extended eucledian algorithm to calculate M_i and m_i though. Other than that, the formula can be calculated within reasonable effort.

euccastro 2020-12-28T11:16:17.076400Z

https://en.wikipedia.org/wiki/Chinese_remainder_theorem

euccastro 2020-12-28T11:17:58.076900Z

here's how you would implement it: https://brilliant.org/wiki/chinese-remainder-theorem/

euccastro 2020-12-28T11:18:22.077300Z

(and yes, those numbers are coprimes)

euccastro 2020-12-28T11:18:48.077600Z

there's #adventofcode too πŸ˜‰

Christian 2020-12-28T11:19:12.077900Z

Oh, I haven't seen this channel, thanks πŸ™‚

Christian 2020-12-28T11:20:10.078800Z

I was hoping to solve it myself. I feel like cheating, now that I have a hint.

Christian 2020-12-28T11:20:22.079200Z

Hint might be more of a solution...

euccastro 2020-12-28T11:21:13.080100Z

there's still some work to do

euccastro 2020-12-28T11:22:32.082400Z

but I think that particular puzzle requires knowing that particular bit of number theory. if not, I don't think you can solve it in any other way than rederiving the theorem yourself, which is a bigger ask than any of the other AoC puzzles

1☝️
Christian 2020-12-28T11:22:44.082500Z

I'd love to finish all days and discuss the solutions with others, is there some division of aoc divided by days?

Christian 2020-12-28T11:23:32.084Z

I even watched some youtube videos on modulo-ring-theory but they did not mention the chinese theorem

euccastro 2020-12-28T11:23:36.084100Z

there are per-day threads in that channel. unfortunately some are old enough that you can't see them unless you have a paid Slack account

euccastro 2020-12-28T11:24:28.085Z

I remember having seen it when studying discrete math, but when I got to solve that puzzle I had already seen the spoiler, so I'll never know whether I would have recalled it on my own..

Christian 2020-12-28T11:26:12.086400Z

So far I only had problems with the second adapter in plane part. I do these to learn clojure and it feels bad, when my math knowledge is blocking the path and not the understanding of clojure.

Christian 2020-12-28T11:26:23.086700Z

I'm excited to finish it πŸ™‚

Christian 2020-12-28T11:26:32.087Z

Thanks for the channel and the method hint

euccastro 2020-12-28T11:28:22.087900Z

I think that particular puzzle is the only one where math is a real blocker. in others math insights may get you a faster answer, but problems are still workable if you miss them

Sebastian 2020-12-28T12:12:11.094500Z

I am trying to solve this problem on codewars: "Complete the functionΒ `scramble(str1, str2)`Β that returnsΒ `true`Β if a portion ofΒ `str1`Β characters can be rearranged to matchΒ `str2`, otherwise returnsΒ `false` " - But I am unsure how to approach it. I first did the naive thing and made both strings into sets. However that was not a possible solution, since if a specific character is repeated twice in str2 and only once in str1, then it should return false. Such that: (scramble "javscripts", "javascript") => false . Then I tried a solution of counting the characters and keeping the count in a dictionary. Then by using merge-with and the "-" function I could maintain if a character appeared more often in the str2 string. I tend to overcomplicate these things a lot and was wondering if there are smarter ways to do this? - This is my code so far

(defn character-count [st]
  (reduce #(assoc %1 %2 (inc (%1 %2 0)))
          {}
          (re-seq #"\D" st))
  )

(defn scramble [s1 s2]
  (let [s1-count (character-count s1)
        s2-count (character-count s2)
        total (merge-with - s1-count s2-count)
        ]
    (not (> (count
              (filter false?
                           (for [[k x] total
                                 :when (or (< x 0) (not (contains? s1-count k)))
                                 ]
                             false)))
            0))))
Link to task: https://www.codewars.com/kata/55c04b4cc56a697bb0000048/train/clojure

Sebastian 2020-12-28T12:41:00.097300Z

I realized that I could have used frequencies instead of the character count function

2FO 2020-12-28T12:47:47.098400Z

Hi, I installed CLJ CLI tools on Ubuntu via the following http://clojure.org scripts. How can I uninstall it and remove its dependencies from my system? "Use the linux-install script to download and run the install, which will create the executables /usr/local/bin/clj, /usr/local/bin/clojure, and the directory /usr/local/lib/clojure:" curl -O <https://download.clojure.org/install/linux-install-1.10.1.727.sh> chmod +x linux-install-1.10.1.727.sh sudo ./linux-install-1.10.1.727.sh

2020-12-28T13:00:55.098500Z

There's no need to walk the entire collection in (not (&gt; (count (filter pred smth)) 0)) -- it's better to use some short-circuiting function like some, not-any? etc. Also, in this particular case, there's no need to check all values in total afaics -- you only need to check the keys of the second map to both be present in the first and have compatible value.

1πŸ™Œ1βœ…
roelof 2020-12-28T13:09:28.099600Z

what do the closures do here :

Instead of using a lazy list, imagine two threads are removing tasks from a pile of work. Our work pile will be the list of all integers from 0 to 10000:
user=&gt; (def work (ref (apply list (range 1e5))))
user=&gt; (take 10 @work)
(0 1 2 3 4 5 6 7 8 9)

And the sum will be a ref as well:
user=&gt; (def sum (ref 0))

Write a function which, in a dosync transaction, removes the first number in work and adds it to sum.
Then, in two futures, call that function over and over again until there's no work left. Verify that @sum is 4999950000. Experiment with different combinations of alter and commute–if both are correct, is one faster? Does using deref instead of ensure change the result?
I find this a confusing challenge of the "clojure from the ground up" book

euccastro 2020-12-28T14:40:24.101500Z

what closures?

roelof 2020-12-28T15:11:27.101700Z

I have to make a function and then the text is saying need in two futures to do something but I do not see what the closures should do and wy I need 2 of them

roelof 2020-12-28T15:11:35.101900Z

@euccastro

euccastro 2020-12-28T15:26:21.102100Z

I think you need two futures to test the thread safety of the ref/dosync mechanism

euccastro 2020-12-28T15:26:33.102300Z

i.e., that they do the right thing despite contention

euccastro 2020-12-28T15:28:18.102500Z

the futures just call your function (closure) over and over until (empty? @work)

roelof 2020-12-28T15:44:23.103100Z

oke, so both futures do the same , call the function till work is empty

2020-12-28T15:45:41.104400Z

When trying to use https://github.com/thi-ng/geom, when I try to require <http://thi.ng|thi.ng>.geom.viz.core In my large project I keep getting the error namespace '<http://thi.ng|thi.ng>.color.core' not found. It works fine in an otherwise empty skeleton project. Any hints as to what might cause this?

roelof 2020-12-28T15:47:38.105200Z

Can I the best develop in WSL or can I also do everyhing with Windows ?

2020-12-28T15:48:35.105300Z

I do everything in regular windows (https://github.com/littleli/scoop-clojure makes it easy for me). I've heard good things about WSL2 but haven't tried or needed it personally to do everything in clojure

2020-12-28T15:49:01.105600Z

there's a #clj-on-windows channel that is helpful too

2020-12-28T16:02:46.105800Z

Figured it out. It was a conflicting prefer-method in my project and http://thi.ng.color.core

practicalli-john 2020-12-28T16:25:50.106Z

@roelof WSL is very good if you are used to the Unix command line. Also VS Code has some integration with WSL, making it easier to use with the Calva extension for VS Code.

2020-12-28T16:31:47.106200Z

@kumarshantanu the only difference between ~(+ x y) and (+ ~x ~y) is when the + call happens (during list building, or later when the compiled object is run) - the same variables are added in both cases (but they might have different values later)

roelof 2020-12-28T16:33:17.106500Z

@euccastro

2020-12-28T16:36:30.106700Z

it doesn't install any dependencies, but it does install clj and clojure to /usr/local. it also creates some dot directories for cache and settings at runtime of clj and clojure, including ~/.clojure and ~/.m2 which is shared by other applications using the maving package system

1πŸ™
2020-12-28T16:37:01.106900Z

I wonder if there's an authoritative list though

1πŸ‘
FHE 2020-12-28T17:38:30.108200Z

Hi. Does anyone here know how to get CIDER going in Doom Emacs?

FHE 2020-12-28T17:38:32.108400Z

(I have also asked this question in the Doom Emacs Discord channel.)

FHE 2020-12-28T17:39:54.109800Z

I don't know which is higher: The fraction of Clojure/ClojureScript programmers who use Doom Emacs, or the fraction of Doom Emacs users who program in Clojure/ClojureScript.

FHE 2020-12-28T17:42:54.111300Z

Heart of the question is whether uncommenting in the "clojure" line (which sits commented out along with lines for lots of other languages etc by default) in the init.el file in the .doom.d folder (and running 'doom sync' of course) is enough. The loading stuff that triggered in Emacs seems to have included some mention of CIDER, but maybe it's a separate install??

FHE 2020-12-28T17:46:23.113200Z

By the way, that init.el file in the .doom.d folder refers to Doom modules, and I'm not clear on what those are. in vanilla init.el file: (defvar my packages '( [...] clojure-mode )) in doom init.el: (doom! :input [...] clojure ) ...but the vanilla config also contains a separate line just underneath: cider

FHE 2020-12-28T17:47:05.113900Z

I don't know how to use CIDER yet, but I do see that my doom emacs seems to recognize the 'cider-jack-in' M-x command (or whatever it is), so that in itself seems to prove the doom input clojure thing includes clojure-mode AND cider. Still, it would be nice to know for sure what a Doom Emacs module does.

roelof 2020-12-28T17:51:35.114900Z

Can anyone what is a good way to learn to make website's with clojure ? So any tutorials which I can follow or free books to read

benny 2020-12-28T17:52:33.115300Z

@factorhengineering what channel in the Doom Emacs Discord? I think it's more appropriate there and I will try to help out

2020-12-28T17:52:51.115400Z

Someone in this channel might know, but there is also a #cider channel on this Slack community that might be a more knowledgeable environment for your questions.

benny 2020-12-28T17:58:06.117400Z

@roelof Fulcro has lots of videos and a very in-depth book. But it's also a full buy-in framework which I consider very well thought out. This is what I think of when I read free and tutorials. A more simpler option would be to check the beta book of "Web Development with Clojure, Third Edition" but that's not free

2020-12-28T17:59:02.118Z

there's also luminus, which is extensively documented (it's what "Web Development with Clojure" uses)

popeye 2020-12-28T18:02:12.118900Z

how dynamic variable is used in the immutable language ? data-readers

2020-12-28T18:03:14.119200Z

the language isn't immutable, vars are mutable containers

2020-12-28T18:04:25.120400Z

in particular, dynamic vars (which have names that are *earmuffed* by convention), can be set in a way that's visible to functions you can call, without changing what parent functions see, this is called dynamic binding

2020-12-28T18:05:26.121300Z

we encourage immutable code (and our standard data collections are immutable) - we use dynamic binding because it's safer than regular mutation

seancorfield 2020-12-28T18:10:42.121400Z

@factorhengineering Zulip is organized in "streams" (like Slack's "channels") and then the discussion in each stream is organized into "topics" (sort of like Slack's "threads", except every new conversation is a separate topic with its own title). If you can see that much in Zulip's UI then you just need to find the slack-archive stream and when you view that stream you will see a separate topic for each of Slack's channels (at least the ones that are being mirrored into Zulip). The beginners stream is a separate stream from slack-archive (which contains a beginners topic -- which is the archive of Slack's #beginners channel). The slack-archive stream is the only stream in Zulip that is directly organized that way because it is populated via a bot here in Slack. Everything else in Zulip is organized according to people starting specific conversations (topics) in the various streams.

popeye 2020-12-28T18:11:03.121900Z

@noisesmith Any example to understand it more?

2020-12-28T18:13:18.122200Z

(cmd)user=&gt; (def ^:dynamic *verbose* false)
#'user/*verbose*
(ins)user=&gt; (defn f [x] (if *verbose* (println "found" x)) x)
#'user/f
(cmd)user=&gt; (f 2)
2
(ins)user=&gt; (binding [*verbose* true] (f 2))
found 2
2

2020-12-28T18:14:08.123200Z

so what those vars are often used for is behaviors - where you want a changed behavior inside some block of code without having a config argument to keep track of

2020-12-28T18:14:45.123900Z

with *data-readers* - the use case is that inside one block of code you are loading a config that uses specific readers

2020-12-28T18:15:18.124600Z

you don't want to change the behavior of all clojure's code that reads data, just the usage inside a specific context

2020-12-28T18:15:51.125400Z

so you use binding to add / modify the readers, and you know the behavior is only being configured inside that binding block and the things it calls

2020-12-28T18:17:02.126400Z

binding is based on the call stack, and if you use standard clojure functions, it even works when a new thread is created

2020-12-28T18:17:54.126700Z

(cmd)user=&gt; (future (Thread/sleep 1000) (binding [*verbose* true] (f 2)))
#object[clojure.core$future_call$reify__8454 0x3703bf3c {:status :pending, :val nil}]
user=&gt; found 2

(ins)user=&gt; @*1
2

2020-12-28T18:21:49.128200Z

so for example the case where you had two threads that are each reading a config file, without a dynamic var either you need a complex coordination to manage the global configuration of the readers, or you need to add an argument to the read function that specifies the readers - someone decided that having a dynamic var was simpler

2020-12-28T18:22:27.128600Z

in practice, dynamic vars are used quite rarely in my experience

popeye 2020-12-28T18:27:29.128900Z

Yeah I understood @noisesmith, Thanks

popeye 2020-12-28T18:27:36.129200Z

what is @*1 ?

2020-12-28T18:28:13.130Z

*1 is always the last value the repl returned (there's also *2 and *3 for the values before that

clyfe 2020-12-28T18:28:42.130100Z

https://github.com/duct-framework/duct

2020-12-28T18:29:13.130900Z

(ins)user=&gt; "first"
"first"
(ins)user=&gt; "second"
"second"
(ins)user=&gt; "third"
"third"
(ins)user=&gt; [*1 *2 *3]
["third" "second" "first"]

2020-12-28T18:29:26.131800Z

@ is a reader macro that expands to a call to deref

2020-12-28T18:29:40.132400Z

user=&gt; `@f
(clojure.core/deref user/f)

2020-12-28T18:29:41.132500Z

It won't answer all of your questions, but the Clojure cheatsheet can be a handy way to look up some things like that: https://jafingerhut.github.io/. https://clojure.org/api/cheatsheet

2020-12-28T18:30:33.133200Z

@popeyepwr your repl probably prints out an explanation of *1 etc. and other values like *e at startup - most people don't read things like that though

2020-12-28T18:31:21.134200Z

(we are trained from many examples that big blocks of printout at the start of things are usually irrelevant, usually some kind of advertisement or legal boilerplate)

1πŸ™Œ
chrisulloa 2020-12-28T18:46:30.138100Z

How would you describe the benefit of this

(into [] (comp (map fn-1) (map fn-2) ...) coll)
over this
(-&gt;&gt; coll (map (comp fn-1 fn-2 ...)) (into []))
? I was thinking that the second example doesn’t leave room in the comp for any filter/removes. Another thing I was thinking was that composing functions (comp fn-1 fn-2 fn-3) leads to (fn-3 (fn-2 (fn-1 val))) which builds a larger intermediate stack than what would occur in the first block for each value being processed.

2020-12-28T18:48:22.138600Z

the benefit of the transducing version is that the -&gt;&gt; version creates lazy seqs that aren't needed

1πŸ‘
2020-12-28T18:48:58.139200Z

the comp version still builds up a stack, it just doesn't build the lazy-seqs between the stack levels

2020-12-28T18:49:35.139900Z

it actually builds and unbuilds the stack once per item, instead of once per function, but that's good because it's much cheaper than lazy-seq building

1πŸ‘
popeye 2020-12-28T18:50:51.140800Z

Thanks @noisesmith , For your detailed explanation, It helped me

1🍻
2020-12-28T18:51:06.141200Z

(many people are used to "smart" compilers that automatically do things like removing unneeded intermediates, clojure intentionally avoids that kind of cleverness)

roelof 2020-12-28T18:52:07.141900Z

why do I get here a illigalState error message :

; Write a function which, in a dosync transaction, removes the first number in 
; work and adds it to sum. Then, in two futures, call that function over and 
; over again until there's no work left. Verify that @sum is 4999950000. 
; Experiment with different combinations of alter and commute–if both are 
; correct, is one faster? Does using deref instead of ensure change the result?

(defn add-dosync[]
  (dosync
     (alter @sum4 + (first work) )))


(defn future1 [] 
  (future(seq @work) add-dosync))

(defn future2[] 
  (future(seq @work) add-dosync))

chrisulloa 2020-12-28T18:53:29.142400Z

thank you @noisesmith

2020-12-28T18:53:30.142500Z

@roelof what is the full error message?

2020-12-28T18:54:06.143300Z

@roelof also what is sum4 - for add-dosync to make sense it needs to be a ref to another container you can deref, which seems very weird

roelof 2020-12-28T18:54:49.144100Z

; Execution error (IllegalStateException) at ground-up.chapter6/eval14308 (form-init6272265265852733152.clj:88).
; No transaction running

2020-12-28T18:54:49.144200Z

also (future (seq x) f) calls seq (which does very little) then returns f without calling it

roelof 2020-12-28T18:55:29.144400Z

moment

roelof 2020-12-28T18:55:34.144700Z

; Instead of using a lazy list, imagine two threads are removing tasks from a pile
; of work. Our work pile will be the list of all integers from 0 to 10000:

(def work (ref (apply list (range 1e5))))

; And the sum will be a ref as well:
(def sum4 (ref 0))

; Write a function which, in a dosync transaction, removes the first number in 
; work and adds it to sum. Then, in two futures, call that function over and 
; over again until there's no work left. Verify that @sum is 4999950000. 
; Experiment with different combinations of alter and commute–if both are 
; correct, is one faster? Does using deref instead of ensure change the result?

(defn add-dosync[]
  (dosync
     (alter @sum4 + (first work) )))


(defn future1 [] 
  (future(seq @work) add-dosync))

(defn future2[] 
  (future(seq @work) add-dosync))

(ensure sum4)

2020-12-28T18:55:55.145400Z

you can't alter the number 0

2020-12-28T18:56:12.146100Z

so first off, (alter @sum4 ...) doesn't make sense

roelof 2020-12-28T18:56:12.146200Z

o, I was told by calva to check that work is not empty

2020-12-28T18:56:41.146600Z

(future nil f) creates a delayed result that returns f

2020-12-28T18:57:19.147500Z

(future something-not-nil f) creates a delayed result that also returns f

roelof 2020-12-28T18:58:35.148700Z

oke, So I have to change to (future @work add-dosync)

2020-12-28T18:59:02.149100Z

that derefs work, does noting with it, then returns a function

2020-12-28T18:59:18.149400Z

this isn't how future works at all

2020-12-28T18:59:54.149900Z

also your illegal state is on the last line (ensure sum4)

2020-12-28T19:00:13.150400Z

ensure is for making a transaction retry if its arg changes before the transaction returns

2020-12-28T19:00:30.150800Z

it doesn't do anything valid outside a transaction

roelof 2020-12-28T19:01:24.151500Z

yep, with deref I get a answer of 0

2020-12-28T19:01:36.152Z

right, because you never call add-dosync

2020-12-28T19:01:51.152500Z

you just create threads that return it (and never reference the threads again)

2020-12-28T19:02:22.153300Z

in fact, you never even reference the function definitions that would have created those threads (another problem with this code)

roelof 2020-12-28T19:02:40.153800Z

hmm back to the book (clojure from the ground up) to find out what I do wrong

2020-12-28T19:02:47.154Z

that's a good idea

2020-12-28T19:03:19.154700Z

a simplified version: (future (f x)) calls f on x in a new thread - (future f) doesn't do anything interesting

2020-12-28T19:04:15.155300Z

you probably got it mixed up with the way alter works (where you pass it some place, and a function that alters what is in that place)

2020-12-28T19:04:59.155900Z

but you also got alter wrong, by giving it the value in the place, instead of the place itself

2FO 2020-12-28T19:05:06.156Z

So I guess its just a case of deleting the dot directories that I can find?

euccastro 2020-12-28T19:05:30.156300Z

yes

2020-12-28T19:06:18.156700Z

sure - maybe someone else has the official doc on this (or, also possible, nobody made that doc)

roelof 2020-12-28T19:07:05.157200Z

thanks, this is a very difficult chapter

2020-12-28T19:08:42.158800Z

this is the repo for the installer if that helps - I don't see an uninstall or a document describing what it installs https://github.com/clojure/brew-install

roelof 2020-12-28T19:08:44.159100Z

if I understand you , I have to do something as add-dosyn &lt;number&gt; but according to the challenge I have to do something in the function to add a number to the sum

roelof 2020-12-28T19:09:07.159400Z

and not in the future

roelof 2020-12-28T19:10:26.159900Z

oke, as you can see in later discussion I hit a lot of walls with this one

2020-12-28T19:11:41.161300Z

starting from the part of the code that seems closest to something that could work:

(dosync
     (alter @sum4 + (first work) ))
it becomes something almost reasonable if we change it to
(dosync
     (alter sum4 + (first @work)))
but there's still the problem that you also have to remove that first item from work so that no other call tries to use that same item

2020-12-28T19:12:19.162Z

so that becomes, perhaps

(dosync
  (alter sum4 + (first @work))
  (alter work rest))

2020-12-28T19:12:51.162700Z

which adds the item to the sum, and removes it from work, and that's all in one transaction so you know that no other call to the same function used that item

2020-12-28T19:13:25.163300Z

but perhaps you (or the exercise author) had something else in mind - there's enough wrong in the code that I could be on the wrong track about how to fix it

2FO 2020-12-28T19:15:47.163400Z

thanks, I'll check it out, just had a reread of the docs on http://clojure.org; no sign of removal instructions there either

2020-12-28T19:21:16.163600Z

an empirical (but maybe silly) approach would be to make a minimal docker image with java, and run two instances. run the clojure installer in one of them, and find all the differences in the file system

2020-12-28T19:21:22.163800Z

that's probably too much work though

roelof 2020-12-28T19:29:21.165Z

@noisesmith thanks

roelof 2020-12-28T19:29:40.165700Z

now I have to find out how to use that in the future

popeye 2020-12-28T19:29:50.165900Z

In the below code I assumed fun is evaluated if the input is positive and argument is between 16 and 225

popeye 2020-12-28T19:29:51.166100Z

(defn constrained-sqr [x] {:pre [(pos? x)] :post [(> % 16), (< % 225)]} (* x x))

popeye 2020-12-28T19:30:01.166400Z

Is my understanding right?

2020-12-28T19:30:23.166900Z

it will throw an AssertionError if the constraints are not met

2020-12-28T19:30:35.167400Z

it's evaluated up until the point one of the constraints fails

popeye 2020-12-28T19:31:07.168Z

it returned value for (constrained-sqr 7) but fails for (constrained-sqr 17)

popeye 2020-12-28T19:31:09.168200Z

why so?

2020-12-28T19:31:34.168500Z

because 289 is greater than 255

popeye 2020-12-28T19:32:06.169Z

the result should be less? i though it is arguent

2020-12-28T19:32:22.169300Z

:post is a test on the result

2020-12-28T19:32:31.169600Z

(or rather, a vector of tests on the result which must all pass)

roelof 2020-12-28T19:32:51.169900Z

this gives still zero

(defn add-dosync []
  (dosync
  (alter sum4 + (first @work))
  (alter work rest)))


(defn future1 [] 
  (future @work add-dosync))

(defn future2[] 
  (future @work add-dosync))

(deref sum4)

popeye 2020-12-28T19:33:18.170600Z

if i pass 7, it should check for pos? right ... (pos? x)

2020-12-28T19:33:26.170900Z

right

2020-12-28T19:33:43.171300Z

then it tests if the return value is between 16 and 255, exclusive

2020-12-28T19:34:19.172100Z

% in the :post clause is a placehoder for what the function wants to return

popeye 2020-12-28T19:34:22.172200Z

(pos? x) should fail for input 7 right.. since it is not +ve value

2020-12-28T19:34:46.172500Z

user=&gt; (pos? 7)
true

mafcocinco 2020-12-28T19:34:58.172700Z

funny that apples and oranges are quite similar and it seems not unreasonable to be comparing them.

popeye 2020-12-28T19:35:19.173Z

My bad sorry!!!! confused with even, My bad!!!!

popeye 2020-12-28T19:35:40.173400Z

Thanks @noisesmith

2FO 2020-12-28T19:46:18.174100Z

I'd consider it if I had any docker experience.. in the end I deleted ~/.m2 ~/.clojure and any dot directories I could find, then ran timeshift to restore my system to its pre- CLI tools state,

2020-12-28T19:50:56.174300Z

seems like a decent feature request for that repo TBH

1πŸ‘
roelof 2020-12-28T20:00:36.174500Z

thanks, I will look at that one

benny 2020-12-28T20:21:49.177600Z

is there a LIFO stack based list-like type? I'm trying to keep the last 100 x's only

seancorfield 2020-12-28T20:27:31.180400Z

benny a LIFO stack can use a vector with conj to add, peek to look at the "head" and pop to remove the "head" (it actually uses the backend of the vector, not the front end). But "keep the last 100 x's" only sounds more like a FIFO queue to me (where you would pop off the oldest item once you hit the queue limit). There's a clojure.lang.PersistentQueue for that.

seancorfield 2020-12-28T20:27:50.180600Z

@b ^

benny 2020-12-28T20:30:03.182Z

@seancorfield oh yes, thanks! FIFO is right πŸ˜‰

emilaasa 2020-12-28T20:31:32.182500Z

Are you queueing work or just keeping a collection of things?

benny 2020-12-28T20:35:11.183500Z

@emilaasa just keeping a running tally of events and when a certain trigger happens I want to dump the last 100 events

emilaasa 2020-12-28T20:36:48.185200Z

Sounds like a good use for PersistentQueue! Just wanted to make a quick shoutout to java.util.concurrent which also has a lot of nice data structures for queueing work and orchestrating programs in general.

Marcus 2020-12-28T21:56:03.186600Z

Hi all! How would you do IPC in Clojure?

seancorfield 2020-12-28T22:23:26.187600Z

@marcus.akre "It depends". Is this communication only ever going to be between two Clojure processes, or might other tech be used at any point for one or more of these processes?

Marcus 2020-12-28T22:26:38.190600Z

clojure only.. on same machine

seancorfield 2020-12-28T22:26:44.190700Z

There is no single "best" answer to how to do IPC in general but there are lots of possible solutions depending on what sort of trade offs you want to make. Is this bidirectional or more client/server? How robust does it need to be in the face of network issues? What about latency considerations? How large are the data packets you want to exchange? Maybe using a shared database and polling is a reasonable choice. Maybe using an external message queue service is a reasonable choice. Maybe using a REST-style API is appropriate.

seancorfield 2020-12-28T22:28:33.192100Z

Since you say Clojure only on the same machine: are these processes in separate JVMs or could they both run within the same JVM? (then it wouldn't really be IPC and you could use any number of in-memory / in-process mechanisms)

Marcus 2020-12-28T22:30:50.193400Z

I am not sure. If you start two separate java applications on the same host, will it then be the same JVM?

Marcus 2020-12-28T22:32:56.194600Z

How could I access shared memory in such cases?

seancorfield 2020-12-28T22:34:50.195100Z

Each Java application you start runs a separate JVM.

seancorfield 2020-12-28T22:35:19.195600Z

I guess at this point, the question is more: what problem are you actually trying to solve here?

1βž•
seancorfield 2020-12-28T22:36:18.196300Z

(depending on exactly what problem you're trying to solve, maybe you could use a single JVM?)

Marcus 2020-12-28T22:38:56.197500Z

I am trying to implement a light weight queue handler that other clojure programs can post jobs to

Marcus 2020-12-28T22:42:10.198800Z

Of course, this can be solved in a number of ways.. ..even just by using existing software.

clyfe 2020-12-28T22:42:27.199Z

https://github.com/layerware/pgqueue

Marcus 2020-12-28T22:42:48.199500Z

thanks! πŸ™‚

clyfe 2020-12-28T22:46:43.201600Z

what is light weight about it? does the queue need to persist to survive restarts? does it have to ensure exact "execute once" semantics? is speed the main concern above the prior bits?

clyfe 2020-12-28T22:47:02.201800Z

You do IPC same as in any other language, named pipe, socket etc

clyfe 2020-12-28T22:47:52.202500Z

An interesting case (depending on security concerns) is to use a socket repl (prepl preferred) https://nrepl.org/nrepl/0.8/alternatives.html

clyfe 2020-12-28T22:48:45.203100Z

Work being planted by sending a form to the worker process

seancorfield 2020-12-28T22:50:17.204800Z

Using a prepl would be a nice Clojure-centric approach -- that thinks outside the box!

1πŸ™‚
seancorfield 2020-12-28T22:50:47.205500Z

Although it is synchronous (unless you send futures).

Marcus 2020-12-28T22:50:59.206Z

It just needs to process jobs sequentially as they come in.. no persistence or execute once

seancorfield 2020-12-28T22:51:12.206600Z

I guess it depends on what feedback you want to get from the process, if any.

Marcus 2020-12-28T22:51:16.206800Z

I'll check prepl

Marcus 2020-12-28T22:53:11.208300Z

I don't need any feedback from the process either

Dimitar Uzunov 2020-12-28T22:54:06.209600Z

Not an expert on this topic, but I appreciate the discussion. Lately at work it seems like adding Redis or RabbitMQ seems to be the default overkill solution to any IPC..

seancorfield 2020-12-28T22:54:12.209800Z

I'm curious as to what problem this solves that you couldn't solve with just executing code in a thread pool directly within each program? Using an agent, for example.

seancorfield 2020-12-28T22:54:42.210300Z

(or a plain old Java executor -- or just using future directly)

Marcus 2020-12-28T22:56:53.211500Z

@seancorfield I am trying to learn both Clojure and kind of Java at the same time. πŸ™‚ How can I utilize core.async or agent across separate clojure programs?

Marcus 2020-12-28T22:57:16.212Z

Because that was the first thing I was thinking about.

Marcus 2020-12-28T22:57:48.212400Z

e.g. by separating things in libraries etc

1πŸ˜†
seancorfield 2020-12-28T22:59:46.213100Z

core.async and agent's are for in-process stuff.

seancorfield 2020-12-28T23:00:06.213700Z

My question was: why write separate programs for this, at all?

seancorfield 2020-12-28T23:01:42.215300Z

If it's just as a learning exercise, fair enough, but you need to figure out what you're trying to learn πŸ™‚ Is it about using sockets and reading/writing data on them? Is it about queuing? Or job control in general?

seancorfield 2020-12-28T23:02:22.216Z

What are the "jobs" that you want to be able to run? Just Clojure code expressions?

seancorfield 2020-12-28T23:03:20.217Z

How does Java fit into this? (even from a learning p.o.v.) That's a genuine question: I'm not sure what you'd be learning about Java in the scenario above...

Marcus 2020-12-28T23:06:56.219600Z

It is a command handler for a CQRS system. So it is just Clojure code expressions. I want to put it into a separate program to be able to use it through different interfaces. E.g. via a web server and command line etc. I am not trying to learn Java really, but of course some Java concepts seeps through. :)

2020-12-28T23:24:38.222Z

@marcus.akre while it's trivial to send clojure code to another process (you can just start up a repl as a socket handler), I don't think it's a very good API for IPC

2020-12-28T23:25:03.222400Z

for the same reason you wouldn't just use SSH and send shell commands

Marcus 2020-12-28T23:29:20.222600Z

ok thanks