Fork me on GitHub
#beginners
<
2022-02-20
>
quan xing06:02:54

(def task-run-state (atom true))

(defn task-stop
  []
  (reset! task-run-state false)
  )
(defn task-start
  []
  (reset! task-run-state true))

(defn run
  []
  (println "run!")
  (loop [x 10]
    (println "task-run-state:" @task-run-state)
      (when (and (> x 0) @task-run-state)
        (println "run:" x)
        (Thread/sleep 1000)
        
        (recur (- x 1))))
    )
(comment

  (let [r (future (run))]
    @r)

  (task-start)
  (task-stop)

  )
When I press alt+enter calc (let [r (future (run))] @r) and loop print . why I press alt+enter calc (task-stop to change atom task-run-state , the program is run continue, why is not stop?

seancorfield06:02:12

Because you have @r so that will wait for the future to complete.

seancorfield06:02:43

So evaluating the let is just going to run until it completes. Other evaluations won't happen until it has finished.

seancorfield06:02:18

If you evaluate just (future (run)) it will "complete", i.e., return a value, immediately because you'll get the future object itself back while the code runs in another thread. Then you can eval (task-stop) and you'll see it affect the loop.

seancorfield06:02:14

Like so (using a REPL directly):

user=> (future (run))
run!
task-run-state: true
run: 10
#object[clojure.core$future_call$reify__8477 0x2b9b7f1f {:status :pending, :val nil}]
user=> task-run-state: true
run: 9
task-run-state: true
run: 8
task-run-state: true
run: 7
task-run-state: true
run: 6
(task-stop)
false
user=> task-run-state: false
It stops here.

seancorfield06:02:57

With @r, you see the first expression run to completion before the (task-stop) can run:

user=> (let [r (future (run))] @r)
run!
task-run-state: true
run: 10
task-run-state: true
run: 9
task-run-state: true
run: 8
task-run-state: true
run: 7
task-run-state: true
run: 6
task-run-state: true
run: 5
(task-stop)
task-run-state: true
run: 4
task-run-state: true
run: 3
task-run-state: true
run: 2
task-run-state: true
run: 1
task-run-state: true
nil
user=> false

quan xing06:02:35

ok. thanks. I want to run a task in the background and be able to manually stop it. am i wrote this code correctly

Matej Šarlija14:02:21

Hi, what book of the many for Clojure would you recommend after picking up some syntax - so that it deals mostly with database access (or similar) and api building?

practicalli-johnny14:02:45

I've also done some guides on using next.jdbc to build a server side application https://practical.li/clojure-web-services/projects/banking-on-clojure/development-database.html

👍 2
seancorfield21:02:02

Clojure Applied is a good book about practical use of Clojure (although the author says they would play down records if they do a 2nd ed and focus more on plain hash maps).

Adir Ohayon16:02:12

Hello everyone, a question regarding ->> , I have searched through the https://clojuredocs.org/clojure.core/-%3E%3E and I understood what it's doing but I'm very unsure when to use it. The docs have a nice example (the one using reduce) which makes a lot of sense in terms of readability but I'm quite sure it's not something I would have came up with (perhaps it's something that comes with experience but I'd still rather ask), so - any thumb rule when we want to use this?

solf16:02:22

You can check the threading macro guide: https://clojure.org/guides/threading_macros

solf16:02:29

Are you comfortable with ->, or is it both threading macros that you find hard to use?

practicalli-johnny16:02:49

When to use it is down to preference. The more nested expressions in the top-level expression, the more likely the thread macros would be used. If a threaded macro is macro-expanded, then an equo Clojure nested expression is returned.

practicalli-johnny16:02:52

The thread macro can make it clearer as to the flow of transformations being applied to the data. For a nested expression, then it is read from the most nested expression outwards to understand the flow.

Adir Ohayon16:02:55

Ty for the quick replies! @U7S5E44DB - I find -> quite intuitive to use (as it's like the . sign for objects in Python (although we have no objects here, that's some similarity which eases the understanding that I hope is correct 🙂 ) It's about the ->> which I don't understand quite well @U05254DQM gave some nice insights that help, I'll combine it was the macro guide sent which is sure to be helpful. Yet again, ty both!

practicalli-johnny16:02:14

One final point. The thread macros can make debugging a flow easier. I use the #_ to comment one of more of the expressions in the thread. Then evaluate the top level form to see the results of the partial flow

Alex Miller (Clojure team)16:02:31

Use ->> to flow a sequence through a series of transformations

practicalli-johnny16:02:15

There is an example of this in the video https://youtu.be/hpz2vHaTz44

Godwin Ko22:02:00

I’m following the style suggested by Stuart Sierra https://stuartsierra.com/2018/07/06/threading-with-style

Nathan Rogers17:02:36

Hello. I have learned and forgotten the syntax and notation for Clojure a few times, and written some fun toy applications with the core language, but I don't know anything about Lein, or installing and managing dependencies, or whatever other tools there are. I've learned to write and evaluate with emacs and cider pretty effectively as I do with SBCL, but I don't know anything beyond that. Q: If anyone can share resources for how to learn the environment for someone who already is familiar with the core language, it would be greatly appreciated.

walterl18:02:27

Maybe start with the https://clojure.org/guides/deps_and_cli, and check out https://github.com/seancorfield/deps-new if you don't want to set everything up by hand.

👀 1
practicalli-johnny07:02:27

A practical guide to the Clojure CLI tooling for working with Clojure projects https://practical.li/clojure/clojure-cli/

Neil Barrett18:02:42

Hi everyone - I'm reading 'The Joy of Clojure (2ed)'. Two functions are defined on p126 illustrating the difference between rest and next with regard to lazy sequences. I don't understand the difference, especially since when I run the code I do not get the claimed results. Could someone clarify what is going on here please? - Am I allowed to paste the yellow block from the book?

andy.fingerhut19:02:56

I think it should be fine pasting short snippets of code here. I also wouldn't be surprised if there were a public repo somewhere with those code snippets in it.

andy.fingerhut19:02:31

It is at least possible that this level of detailed behavior might have been intentionally changed in some older version of Clojure.

Neil Barrett19:02:50

Thanks Andy - I'll paste it

Neil Barrett19:02:36

Thanks for looking at it. Do you use rest or next in your code? next seems more useful when used with when-let but rest seems to be more highly recommended.

andy.fingerhut19:02:13

I am primarily a hobbyist in Clojure, and in the code I have written, I've never noticed the difference between rest vs. next.

Neil Barrett19:02:46

I'm also a hobbyist! It's great fun, isn't it?

andy.fingerhut19:02:58

I do not know why, but I see slightly different output depending on whether I run that code with Clojure 1.6.0 vs. later versions of Clojure.

andy.fingerhut19:02:04

I believe the general recommendation is that if you want to guarantee control over how many things are evaluated in a sequence, then do not use lazy sequences. Use things like loop instead.

andy.fingerhut19:02:39

Because lazy sequences can in many cases evaluate more elements than the minimum possible.

andy.fingerhut19:02:10

Joy of Clojure 2nd ed has a publish year of 2014. Clojure 1.6.0 was release 2014-Mar-25, Clojure 1.7.0 on 2015-Jun-30.

Neil Barrett19:02:13

Thanks Andy - I'll carry on reading and see whether that calms my nerves

seancorfield21:02:28

@neil.barrett16 Something changed between Clojure 1.6 and 1.7 that caused this difference to go away -- I suspect iterate changed:

(! 748)-> clj -M:1.6
Clojure 1.6.0
user=> (def very-lazy (-> (iterate #(do (print \.) (inc %)) 1)
rest rest rest))
..#'user/very-lazy
user=> (def less-lazy (-> (iterate #(do (print \.) (inc %)) 1)
next next next))
...#'user/less-lazy
user=> (println (first very-lazy))
.4
nil
user=> (println (first less-lazy))
4
nil
user=> ^D

Sun Feb 20 13:35:00
(sean)-(jobs:0)-(~/clojure/fresh)
(! 749)-> clj -M:1.7
Clojure 1.7.0
user=> (def very-lazy (-> (iterate #(do (print \.) (inc %)) 1)
rest rest rest))
..#'user/very-lazy
user=> (def less-lazy (-> (iterate #(do (print \.) (inc %)) 1)
next next next))
..#'user/less-lazy
user=> (println (first very-lazy))
.4
nil
user=> (println (first less-lazy))
.4
nil
user=> 

seancorfield21:02:10

Yes, iterate changed:

;; still in the 1.7 REPL
user=> (source iterate)
(defn iterate
  "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
  {:added "1.0"
   :static true}
  [f x] (clojure.lang.Iterate/create f x) )
nil
user=> ^D

Sun Feb 20 13:36:39
(sean)-(jobs:0)-(~/clojure/fresh)
(! 750)-> clj -M:1.6
Clojure 1.6.0
user=> (source iterate)
(defn iterate
  "Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects"
  {:added "1.0"
   :static true}
  [f x] (cons x (lazy-seq (iterate f (f x)))))

seancorfield21:02:00

So the difference between rest vs. next is correct in the book but the function they used to illustrate it changed.

seancorfield21:02:59

And if we look at the changes for Clojure 1.7 https://github.com/clojure/clojure/blob/master/changes.md#changes-to-clojure-in-version-17 we see: • 2.6 Faster reduce and iterator paths - iterate - implements IReduceInit So I expect that's the root cause of the difference.

Neil Barrett22:02:30

Thank you, Sean - that's a great help.