macroexpand doseq in Babashka vs in Clojure - clojure

In Babashka v0.6.2, I can call macroexpand on the for macro and the output is something like this:
user=> (macroexpand '(for [i (range 10)] i))
(clojure.core/let [iter__1755__auto__ (clojure.core/fn iter__147 [s__148] (clojure.core/lazy-seq (loop [s__148 s__148] (clojure.core/let [s__148 (clojure.core/seq s__148)] (clojure.core/when s__148 (if (clojure.core/chunked-seq? s__148) (clojure.core/let [c__1753__auto__ (clojure.core/chunk-first s__148) size__1754__auto__ (clojure.core/int (clojure.core/count c__1753__auto__)) b__150 (clojure.core/chunk-buffer size__1754__auto__)] (if (loop [i__149 (clojure.core/int 0)] (if (clojure.core/< i__149 size__1754__auto__) (clojure.core/let [i (clojure.core/nth c__1753__auto__ i__149)] (do (clojure.core/chunk-append b__150 i) (recur (clojure.core/unchecked-inc i__149)))) true)) (clojure.core/chunk-cons (clojure.core/chunk b__150) (iter__147 (clojure.core/chunk-rest s__148))) (clojure.core/chunk-cons (clojure.core/chunk b__150) nil))) (clojure.core/let [i (clojure.core/first s__148)] (clojure.core/cons i (iter__147 (clojure.core/rest s__148))))))))))] (iter__1755__auto__ (range 10)))
However, if I do the same for doseq, then I get the same form back:
user=> (macroexpand '(doseq [i (range 10)] (println i)))
(doseq [i (range 10)] (println i))
But this latter expression works in Clojure as expected:
erdos.assert=> (macroexpand '(doseq [i (range 10)] (println i)))
(loop* [seq_2318 (clojure.core/seq (range 10)) chunk_2319 nil count_2320 0 i_2321 0] (if (clojure.core/< i_2321 count_2320) (clojure.core/let [i (.nth chunk_2319 i_2321)] (do (println i)) (recur seq_2318 chunk_2319 count_2320 (clojure.core/unchecked-inc i_2321))) (clojure.core/when-let [seq_2318 (clojure.core/seq seq_2318)] (if (clojure.core/chunked-seq? seq_2318) (clojure.core/let [c__4917__auto__ (clojure.core/chunk-first seq_2318)] (recur (clojure.core/chunk-rest seq_2318) c__4917__auto__ (clojure.core/int (clojure.core/count c__4917__auto__)) (clojure.core/int 0))) (clojure.core/let [i (clojure.core/first seq_2318)] (do (println i)) (recur (clojure.core/next seq_2318) nil 0 0))))))
Perhaps doseq is like a special form in Babashka? What is the reason for this distinction of doseq?
How should I modify macroexpand so that all macros are expanded?

Some things are indeed specially treated in the interpreter and not implemented as regular macros. This is an historical artifact from the early beginnings when babashka didn't even support macros. This may change in the future.
EDIT: this is now already fixed on master. Thanks for the PR erdos.

Related

How to end dotimes clojure

I am trying to make a guess the number game in clojure but I keep getting an error saying I can only recur from tail position
(def n (rand-int 100))
(prn n)
(println "You have 10 guesses :D")
(println "HINT: My number is between 1 and 100")
(dotimes [i 10]
(def guess (read-line))
(if (= guess str(n))
(recur (println "Correct!") (println "Incorrect"))))
(I am new to clojure)
dotimes is used to execute the body for sideeffects that exact amount given; there is no means to break - except throwing
loop (or functions) are recur targets. Next you would have to count down the attempts so you can stop, if the user did not guess it:
(loop [attempts 10]
; ...
(recur (dec attempts)))
There are also other problematic things:
Don't def inside other forms. Use let instead.
str(n) will throw, as it will try to call n (ClassCastException java.lang.Long cannot be cast to clojure.lang.IFn)
recuring with println looks fishy, since println returns always nil
How do you end dotimes? You don't. Try using loop instead. There are a lot of issues with your code but that's a start.
though this is discouraged and counterclojurish to even think of short circuiting the execution this way, it is still totally possible with macros (purely for education and fun)
(defmacro return [& x]
`(list '~'return (do ~#x)))
(defmacro dotimes+ [[i n] & body]
`(loop [~i 0 res# nil]
(cond (and (list? res#) (= '~'return (first res#))) (second res#)
(< ~i ~n) (recur (inc ~i) (do ~#body))
:else res#)))
can be used like this:
user> (dotimes+ [i 10]
(println i)
(if (== i 5) (return :short-circuited)))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
:short-circuited
user> (dotimes+ [i 10]
(println i)
(if (== i 5) (return)))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
nil
user> (dotimes+ [i 10]
(println i))
;; 0
;; 1
;; 2
;; 3
;; 4
;; 5
;; 6
;; 7
;; 8
;; 9
nil
notice, that it still expects the return macro to be called in tail position (similar to recur in loop macro)
(dotimes+ [x 4]
(println "attempt" (inc x))
(let [answer (read-line)]
(println "answer is:" answer)
(if (= answer "yes")
(return "YEAH!!!")
(println "WRONG!"))))

Sleeping barber in Clojure

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

How do I rewrite (def) out of this Clojure code?

I have written a game loop based on deWitter's game loop.
However, I am unsure how to transfer it to a more functional state. I realize that there may need to be some mutable state left within the code but are there any general principles for cleaning up extraneous defs?
(ns beepboop.core)
(def ticks-per-second 25)
(def skip-ticks (/ 1000 ticks-per-second))
(def max-frameskip 5)
(defn update []
(println "Updating."))
(defn display [delta]
(println "Displaying with delta: " delta))
(defn -main []
(def *next-tick* (System/currentTimeMillis))
(while true
(def *loops* 0)
(while (and
(> (System/currentTimeMillis)
*next-tick*)
(< *loops*
max-frameskip))
(update)
(def *next-tick* (+ *next-tick* skip-ticks))
(def *loops* (+ *loops* 1)))
(display
(/ (+ (System/currentTimeMillis) skip-ticks (* -1 *next-tick*))
skip-ticks))))
You should use loop and recur for updating your loop variables:
(defn -main []
(loop [next-tick (System/currentTimeMillis)]
(let [next-next
(loop [next-tick next-tick
loops 0]
(if (and (> (System/currentTimeMillis) next-tick)
(< loops max-frameskip))
(do (update)
(recur (+ next-tick skip-ticks) (+ loops 1)))
next-tick))]
(display (/ (+ (System/currentTimeMillis) skip-ticks (- next-next))
skip-ticks))
(recur next-next))))

Does 'concat' break the laziness of 'line-seq'?

The following code appears to force line-seq to read 4 lines from file. Is this some kind of buffering mechanism? Do I need to use lazy-cat here? If so, how can I apply a macro to a sequence as if it were variadic arguments?
(defn char-seq [rdr]
(let [coll (line-seq rdr)]
(apply concat (map (fn [x] (println \,) x) coll))))
(def tmp (char-seq (clojure.contrib.io/reader file)))
;,
;,
;,
;,
#'user/tmp
Part of what you're seeing is due to apply, since it will need to realize as many args as needed by the function definition. E.g.:
user=> (defn foo [& args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
#'user/bar
user=> (defn foo [x & args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
2
#'user/bar
user=> (defn foo [x y & args] nil)
#'user/foo
user=> (def bar (apply foo (iterate #(let [i (inc %)] (println i) i) 0)))
1
2
3
#'user/bar

Project Euler #14 and memoization in Clojure

As a neophyte clojurian, it was recommended to me that I go through the Project Euler problems as a way to learn the language. Its definitely a great way to improve your skills and gain confidence. I just finished up my answer to problem #14. It works fine, but to get it running efficiently I had to implement some memoization. I couldn't use the prepackaged memoize function because of the way my code was structured, and I think it was a good experience to roll my own anyways. My question is if there is a good way to encapsulate my cache within the function itself, or if I have to define an external cache like I have done. Also, any tips to make my code more idiomatic would be appreciated.
(use 'clojure.test)
(def mem (atom {}))
(with-test
(defn chain-length
([x] (chain-length x x 0))
([start-val x c]
(if-let [e (last(find #mem x))]
(let [ret (+ c e)]
(swap! mem assoc start-val ret)
ret)
(if (<= x 1)
(let [ret (+ c 1)]
(swap! mem assoc start-val ret)
ret)
(if (even? x)
(recur start-val (/ x 2) (+ c 1))
(recur start-val (+ 1 (* x 3)) (+ c 1)))))))
(is (= 10 (chain-length 13))))
(with-test
(defn longest-chain
([] (longest-chain 2 0 0))
([c max start-num]
(if (>= c 1000000)
start-num
(let [l (chain-length c)]
(if (> l max)
(recur (+ 1 c) l c)
(recur (+ 1 c) max start-num))))))
(is (= 837799 (longest-chain))))
Since you want the cache to be shared between all invocations of chain-length, you would write chain-length as (let [mem (atom {})] (defn chain-length ...)) so that it would only be visible to chain-length.
In this case, since the longest chain is sufficiently small, you could define chain-length using the naive recursive method and use Clojure's builtin memoize function on that.
Here's an idiomatic(?) version using plain old memoize.
(def chain-length
(memoize
(fn [n]
(cond
(== n 1) 1
(even? n) (inc (chain-length (/ n 2)))
:else (inc (chain-length (inc (* 3 n))))))))
(defn longest-chain [start end]
(reduce (fn [x y]
(if (> (second x) (second y)) x y))
(for [n (range start (inc end))]
[n (chain-length n)])))
If you have an urge to use recur, consider map or reduce first. They often do what you want, and sometimes do it better/faster, since they take advantage of chunked seqs.
(inc x) is like (+ 1 x), but inc is about twice as fast.
You can capture the surrounding environment in a clojure :
(defn my-memoize [f]
(let [cache (atom {})]
(fn [x]
(let [cy (get #cache x)]
(if (nil? cy)
(let [fx (f x)]
(reset! cache (assoc #cache x fx)) fx) cy)))))
(defn mul2 [x] (do (print "Hello") (* 2 x)))
(def mmul2 (my-memoize mul2))
user=> (mmul2 2)
Hello4
user=> (mmul2 2)
4
You see the mul2 funciton is only called once.
So the 'cache' is captured by the clojure and can be used to store the values.