Here is an example from clojure for the brave and true:
(time
(let [butter-promise (promise)]
(doseq [butter [yak-butter-international butter-than-nothing baby-got-yak]]
(future (if-let [satisfactory-butter (satisfactory? (mock-api-call butter))]
(deliver butter-promise satisfactory-butter))))
(println "And the winner is:" #butter-promise)))
What if none of the butter products satisfy our criteria?
(let [butter-promise (promise)]
;; ...
(if-let [winner (deref butter-promise 10000 nil)]
(println "And the winner is:" winner)
(println "Butter timed out."))
Related
The question was born when I was practicing an Observer topic in a tutorial
I am trying to apply the function to the user but cannot use user's data fields like name, surname.
Let's say that the user may have various number of data fields so we must use & args argument. My code that does not work:
(ns observer.core)
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})
(apply
(fn [& args] (println (str "I am " (:name args) " " (:surname args) ".")))
user)
(apply
(fn [& args] (println (str "My sister is " (:name args) " " (:surname args) ".")))
user2)
The output:
I am .
My sister is .
observer.core>
How to fix it regarding that the apply function must be used?
apply converts a map to a seq, i.e.
{:name "Alan" :surname "Smith" :alias "Mike"} becomes ([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
You could put it back into a map, if that is what you need:
(let [user {:name "Alan" :surname "Smith" :alias "Mike"}]
(apply
(fn [& args]
(let [args (into {} args)]
(println (str "I am " (:name args) " " (:surname args) "."))))
user))
but this looks a bit of a stretch to me. I believe the solution could have been better if I knew how this function is supposed to be used.
Usually there are two types of functions: (fn :text "some" :row 25) and (fn {:text "some" :row 25}).
In the spirit of learning:
Check out Clojure - Cheatsheet.
10 years with Clojure, and I still use it daily.
(apply some-func (list x y z)) becomes (some-func x y z), because apply assumes that the second argument is a list (which it then unpacks).
And what you are currently doing is collecting all the arguments back into a list called args
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [& args]
(prn 'ARGS args) ;; lets see what is actually in args
(println (str "I am " (:name args) " " (:surname args) ".")))
user)
;; -> ARGS ([:name "Alan"] [:surname "Smith"] [:alias "Mike"])
;; -> I am .
And the outut is as #akond says.
You could, of course, put 'user' in a vector (or list), but then don't use '&' to collect everything back into a list, (which you would then have to pick stuff out of again):
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [args]
(prn 'ARGS args)
(println (str "I am " (:name args) " " (:surname args) ".")))
[user])
That would give you the output you expected. But this is a bit strange, perhaps, but certainly viable if you must use apply and you can control the "list" part of the argument.
So, #akond's solution is simple and clean.
And augmenting it with Clojure "destructing":
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(apply
(fn [& args]
(let [{:keys [name surname alias]} (into {} args)]
(println (str "I am " name " " surname "." (when alias (str " But call me " alias "!"))))))
user)
I believe you intended to do something like this:
(def user {:name "Alan" :surname "Smith" :alias "Mike"})
(def user2 {:name "Jane" :surname "Smith"})
(defn fn-1
[item]
(println (str "I am " (:name item) " " (:surname item) ".")) )
(defn fn-2
[item]
(println (str "My sister is " (:name item) " " (:surname item) ".")))
(fn-1 user)
(fn-2 user2)
with result:
I am Alan Smith.
My sister is Jane Smith.
One has to wrap a user object or the map by a list.
(ns observer.core)
(defrecord Person [name balance])
(def user (Person. "Alan" 150.34))
(def user2 {:name "Adam" :balance 629.74})
(def observers (atom #{}))
(swap! observers conj (fn [l] (println (str "2. " (:name l)))))
(swap! observers conj (fn [l] (println (str "1. " (:balance l)))))
(println "user")
(vec (map #(apply % (list user)) #observers))
(println "\nuser2")
(vec (map #(apply % (list user2)) #observers))
Output
user
1. 150.34
2. Alan
user2
1. 629.74
2. Adam
observer.core>
I am new to Clojure. As part of practice, I wrote a simple guessing game where the user has to guess a random number chosen by the program between 1-100. I got a basic version working (code snippet 1). Now I want to improve on this by allowing the user to enter an integer from 1 to 100. However the code that I wrote to avoid the user from entering a string is not working (code snippet 2) but the code is not working, no matter what I try.
Code snippet 1 (working)
(ns guessing-game2.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))
(recur (inc times))))))))
Code snippet 2 (not working)
(ns guessing-game.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (and (integer? guess)
(< guess 100))
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))))
(print "Please enter a number")
(recur (inc times))
)
))))
you need to recur outside of the if
(ns guessing-game.core
(:gen-class))
(defn -main []
(let [my-number (inc (rand-int 100))]
(println "I have a number between 1 and 100, guess it: ")
(loop [times 1]
(let [guess (Integer/parseInt (read-line))]
(if (and (integer? guess)
(< guess 100))
(if (= guess my-number)
(do
(println "You have found it in " times " tries!")
times)
(do
(cond
(< guess my-number) (println "My number is bigger, guess again: ")
(> guess my-number) (println "My number is smaller, guess again: "))))
(print "Please enter a number")) ;; <-- moved bracket to here
(recur (inc times))
))))
I'm implementing Sleeping barber using core.async. My current code is:
(def workingtime 10000)
(defn barber [in waiting-room]
(go-loop [served-customers 0]
(let [[v] (alts! [waiting-room in])]
(if (= v :close)
served-customers
(do (Thread/sleep 20)
(recur (inc served-customers)))))))
(defn customers [in waiting-room]
(go-loop [customers-overall 0]
(let [customer-arrival-interval (timeout (+ 10 (rand-int 20)))
[v] (alts! [in customer-arrival-interval])]
(if (= v :close)
customers-overall
(do (>! waiting-room :customer)
(recur (inc customers-overall)))))))
(defn -main [& args]
(let [in (chan)
waiting-room (chan (dropping-buffer 3))
barber-ch (barber in waiting-room)
customers-ch (customers in waiting-room)]
(println "opening the shop for 10 seconds...")
(Thread/sleep workingtime)
(>!! in :close)
(>!! in :close)
(println "closing the shop...")
(println (str "Served " (<!! barber-ch) " customers"))
(println (str "Overall " (<!! customers-ch) " customers came"))))
Is it a correct solution? Can it be improved to make it more Clojure-like?
I wanted to use alt! instead of alts! which makes code easier to read:
(defn barber [in]
(go-loop [served-customers 0]
(alt!
waiting-room (do (Thread/sleep 20)
(recur (inc served-customers)))
in served-customers)))
Runtime throws an exception: Can only recur from tail position. Can I still use alt!?
You could solve the alt!/recur problem by rewriting to:
(defn barber [in]
(go-loop [served-customers 0]
(if (= :waiting-room
(a/alt!
waiting-room ([result] :waiting-room) ;; you could also use result if needed
in ([result] :in))) ;; same here
(do (Thread/sleep 20)
(recur (inc served-customers)))
served-customers)))
Here is an example from http://www.braveclojure.com/core-async/ :
(defn hotdog-machine-v2 [hotdog-count]
(let [in (chan) out (chan)]
(go (loop [hc hotdog-count]
(if (> hc 0)
(let [input (<! in)]
(if (= 3 input)
(do
(>! out "hotdog")
(recur (dec hc)) )
(do
(>! out (Exception. "Not enough payment!"))
(recur hc))))
(do
(close! in)
(close! out)))))
[in out]))
(let [[in out] (hotdog-machine-v2 2)]
(>!! in "pocket lint")
(println (<!! out))
(>!! in 3)
(println (<!! out))
(>!! in 3)
(println (<!! out))
(>!! in 3)
(println (<!! out))
)
If I leave out the channel-closing part, then this code hangs forever, why?
If I run this in the normal case with the close it prints this:
user> (let [[in out] (hotdog-machine-v2 2)]
(>!! in "pocket lint")
(println (<!! out))
(>!! in 3)
(println (<!! out))
(>!! in 3)
(println (<!! out))
(>!! in 3)
(println (<!! out)))
#error {
:cause Not enough payment!
:via
[{:type java.lang.Exception
:message Not enough payment!
... stack trace here ...
[java.lang.Thread run Thread.java 724]]}
hotdog
hotdog
nil ;; <---- look here
That last nil is the result of the last read from out reading the value nil, which is being sent as a result of the channel closing because the machine is out of hotdogs. Without the close that last put (>!! in 3) blocks waiting for somthing to read from the chan which nobody is going to do. By default writes to core.async chans don't succeed in writing until someone is ready to read that value
If I take out the close, and take out the last write it does not print that nil, and does not block:
user> (let [[in out] (hotdog-machine-v2 2)]
(>!! in "pocket lint")
(println (<!! out))
(>!! in 3)
(println (<!! out))
(>!! in 3)
(println (<!! out))
)
#error {
:cause Not enough payment!
:via
[{:type java.lang.Exception
:message Not enough payment!
:at ... stack trace here ...}
hotdog
hotdog
I can launch two threads and they work, but synchronously. What am I missing to get these threads independently launched?
main, thread, and output
(defn -main
[& args]
(do
(let [grid-dim-in [0 5]
mr1-pos [\N 2 4]
mr2-pos [\N 1 5]
mr1-movs "LMLMMRMM"
mr2-movs "RMRMMMLM"]
(reset! grid-dim grid-dim-in)
(reset! mr1-id {:mr1 mr1-pos})
(reset! mr2-id {:mr2 mr2-pos})
(.start (Thread. (rover-thread mr1-id mr1-movs update-work-block)))
(.start (Thread. (rover-thread mr2-id mr2-movs update-work-block))))))
(defn rover-thread [id movs update-ref]
(let [id-key (keys #id)
id-vals (vals #id)]
(doseq [mov movs]
(println "Rover " id-key " is moving ")
(let [new-mov (determine-rover-move (first id-vals) mov)]
(move-rover id new-mov update-ref)
(print "Rover ")
(print (first id-key))
(print " is at ")
(println new-mov)
(Thread/sleep (rand 1000)))))
Rover :mr1 is at [E 2 4]
Rover (:mr1) is moving
Rover :mr1 is at [N 2 5]
Rover (:mr1) is moving
Rover :mr1 is at [N 2 5]
Finished on Thread[main,5,main]
Rover (:mr2) is moving
Rover :mr2 is at [E 1 5]
Rover (:mr2) is moving
Rover :mr2 is at [N 1 6]
Take a close look at these two lines:
(.start (Thread. (rover-thread mr1-id mr1-movs update-work-block)))
(.start (Thread. (rover-thread mr2-id mr2-movs update-work-block))))))
This code evaluates the (rover-thread mr1-id mr1-movs update-work-block) first, and passes the result of that to the constructor of Thread, which is not what you want.
Here's a simple function to illustrate the principle. This doesn't work, because the (f ...) is evaluated before its result it passed to the Thread constructor:
(defn run-thread-thing-wrong []
(let [f (fn [n s]
(doseq [i (range n)]
(prn s i)
(Thread/sleep (rand 1000))))]
(.start (Thread. (f 10 "A")))
(.start (Thread. (f 10 "B"))))
nil)
Here's a version that does work. A function is passed to the Thread constructor instead:
(defn run-thread-thing []
(let [f (fn [n s]
(doseq [i (range n)]
(prn s i)
(Thread/sleep (rand 1000))))]
(.start (Thread. (fn [] (f 10 "A"))))
(.start (Thread. (fn [] (f 10 "B")))))
nil)
Note: instead of (fn [] ....) you can use the short form #(....) for anonymous functions.
Here's another version that does the same, but with a future instead of manually creating threads:
(defn run-thread-thing []
(let [f (fn [n s]
(doseq [i (range n)]
(prn s i)
(Thread/sleep (rand 1000))))]
(future (f 10 "A"))
(future (f 10 "B")))
nil)
Note that in this case, you pass a form to future instead of a function.
This seems like a really good place to use Clojure's agent feature. I am not qualified to fully explain how to use them, but a really good example of their usage can be found here. Starting threads using agents is dead-easy, and I think it is more idiomatic.
The code would look something like,
(def rover1 (agent [mr1-posn mr1-movs mr1-id]))
(def rover2 (agent [mr2-posn mr2-movs mr2-id]))
(defn rover-behave [[posn movs id]]
(send-off *agent* #'rover-behave)
(. Thread (sleep 1000))
(let [new-mov (determine-rover-move posn movs id)
new-posn (posn-after-move posn new-mov)]
;return value updates state of agent
[new-posn movs id]
)
)
(send-off rover1 rover-behave)
(send-off rover2 rover-behave)