The below doesn't seem to work, but I'm not quite sure why. All move-board does is take in a 2D array and return a 2D array, rest of the code is all there. Basically I'm trying to accomplish something like the following python:
While True:
do stuff
if gameover:
print("Game Over!")
break
Clojure that isn't working (prints board once, asks for input, then hangs)
(defn game-loop [board]
(loop [b board]
(if (game-over? b) "Game Over!"
(do (print-board b)
(recur (move-board (read-line) b))))))
We would need to see what your other functions are doing. I
fabricated them minimally to what seems likely, and reindented to make
the if-branch clearer. Your loop also was unnecessary.
(defn game-over? [b] false)
(defn print-board [b] (println b))
(defn move-board [ln b] (println "moving board:" ln))
(defn game-loop [b]
(if (game-over? b)
"Game Over!"
(do (print-board b)
(recur (move-board (read-line) b)))))
(game-loop :bored)
With those top three functions, your loop behaves as expected:
prompting for a single line, infinitely. Well, at least the first
time, but then your "hang" issue is reproduced.
This is likely being caused by this issue with the JVM. Also discussed here.
Related
What is the idiomatic way of printing values inside a let binding ?
When I started developing in Clojure, I wrote code in the REPL, that I then turned into simple let expressions. Being a beginner, I often made mistakes during this (simple) transformation phase.
(let [a (aFn ...)
b (bFn ... a)]
;; error above
)
So I would transform it back to something like that, basically inlining things :
(println "a is" (aFn ...))
(println "b is" (bFn ... (aFn ...)))
(let [a (aFn ...)
b (bFn ... a)]
;; ...
)
It works most of the time thanks to Clojure being nice (immutability, referential transparency..).
Now I do something along the lines of :
(let [a (aFn ...)
_ (println "a is" a)
b (bFn ... a)
_ (println "b is" b)]
;; ...
)
It is an improvement, but it still feels clumsy. What is the proper way to do this ?
You could define a print function that returns its argument:
(defn cl-print [x] (doto x (print)))
Then, it is only a matter of wrapping your expressions:
(let [a (cl-print (aFn ...))
b (cl-print (bFn ... a))]
...)
I tend to take a totally different approach. I never put print statements in my let bindings. I also think you need to be careful about calling a function just to get the value for debugging purposes. While we would like all our functions to be side-effect free, this is not always the case, so calling the funciton just to get a value to print may have unexpected results. There is also the issue of how printing values can impact on laziness and realising of lazy sequences etc.
My approach is to define some debugging functions, which I stick in a 'debug' namespace. I then call these debug functions when needed from inside the body of the function - not in the let binding section. Often, I also define a debug-level var so that I can have some control over debugging verbosity. this allows me to change one var and increase or decrease the amount of information logged/printed.
I've experimented with 'clever' macros to make debugging easier - but to be honest, these usually take more effort to get right than the benefit they provide.
I like having my debug functions in a separate namespace as this helps me ensure I've not left any debugging code in my production version - or it allows me to leave debug statements in there, but have them 'do nothing' by setting an appropriate debug level.
As mentioned by another post, using a debugger can eliminate/reduce the need to have these print statements or debug functions. However, I think debuggers can be a double edged sword as well. Too often, people get into bad debugging hapits where they rely on trace and inspect rather than thinking about and analysing exactly what is going on. This can tend to development driven by too much trial and error and not enough analysis and understanding.
You could start with something as simple as
(def debug-level 20)
(defn debug [lvl prefix val]
(if (>= lvl debug-level)
(println (str prefix ": " val)))
(defn debug1 [prefix v]
(debug 10 prefix v))
(defn debug2 [prefix v]
(debug 20 prefix v))
etc
and then just call
(debug2 :a a)
in the body of your function to have the value of a printed when debug-level is 20 or higher.
I wrote a function that tries to get a y/n (yes/no) answer from a user interactively. It tests if the answer is valid and if not, solicits the user again:
(defn get-valid-answer [question]
(println question)
(loop []
(let [ans (.trim (read-line))]
(if (#{"y" "n"} ans)
ans
(do (println "Please answer \"y\"[yes] or \"n\"[no] only!")
(recur) )))))
The above version with loop-recur does the job but I have nagging feeling that there must be a better (more functional) way to do this. I would prefer to have the read-line call made just once. Could anyone suggest an alternative version not using loop-recur in this scenario but possibly using some (Clojure builtin) macro instead?
Think of a small child asking the same question endlessly until it gets a satisfactory reply, then do the same thing in code. That is to say, take the first valid answer from an endless stream of questions.
Untested, but this should do the trick.
(defn ask []
(println "Please answer \"y\"[yes] or \"n\"[no]:")
(.trim (read-line)))
(defn get-valid-answer [question]
(println question)
(->> (repeatedly ask)
(filter #{"y" "n"})
(first)))
You could also define 'ask' in a let binding, if two functions bothers you.
I have been rewriting Land Of Lisp's orc-battle game in Clojure. During the process I am using a more functional style. I have come up with two methods for writing part of the higher level game loop. One involving loop/recur and the other using doseq and atoms. Here are the two functions:
(defn monster-round [player monsters]
(loop [n 0 p player]
(if (>= n (count monsters))
p
(recur (inc n)
(if (monster-dead? (nth monsters n))
p
(let [r (monster-attack (nth monsters n) p)]
(print (:attack r))
(:player r)))))))
(defn monster-round-2 [player monsters]
(let [p (atom player)]
(doseq [m monsters]
(if (not (monster-dead? m))
(let [r (monster-attack m #p)]
(print (:attack r))
(reset! p (:player r)))))
#p))
I like the second method better because the code is more concise and is easier to follow. Is there any reason why the first approach is better? Or am I missing a different way to do this?
is this equivalent? if so, i prefer it - it's compact, clearer than your solutions (imho!), and functional
(defn monster-round [monsters player]
(if-let [[monster & monsters] monsters]
(recur monsters
(if (monster-dead? monster)
player
(let [r (monster-attack monster player)]
(print (:attack r))
(:player r))))
player))
(note: i changed the argument order to monster-round so that the recur looked nicer)
more generally, you should not have introduced n in your "functional" version (it's not really really functional if you've got an index...). indexing into a sequence is very, very rarely needed. if you had fought the temptation to do that a little harder, i think you would have written the routine above...
but, after writing that, i thought: "hmmm. that's just iterating over monsters. why can't we use a standard form? it's not a for loop because player changes. so it must be a fold (ie a reduce), which carries the player forwards". and then it was easy to write:
(defn- fight [player monster]
(if (monster-dead? monster)
player
(let [r (monster-attack monster player)]
(print (:attack r))
(:player r))))
(defn monster-round [player monsters]
(reduce fight player monsters))
which (if it does what you want) is the Correct Answer(tm).
(maybe i am not answering the question? i think you missed the better way, as above. in general, you should be able to thread the computation around the data structure, which does normally not require mutation; often you can - and should - use the standard forms like map and reduce because they help document the process for others).
I have the following Clojure code to calculate a number with a certain "factorable" property. (what exactly the code does is secondary).
(defn factor-9
([]
(let [digits (take 9 (iterate #(inc %) 1))
nums (map (fn [x] ,(Integer. (apply str x))) (permutations digits))]
(some (fn [x] (and (factor-9 x) x)) nums)))
([n]
(or
(= 1 (count (str n)))
(and (divisible-by-length n) (factor-9 (quot n 10))))))
Now, I'm into TCO and realize that Clojure can only provide tail-recursion if explicitly told so using the recur keyword. So I've rewritten the code to do that (replacing factor-9 with recur being the only difference):
(defn factor-9
([]
(let [digits (take 9 (iterate #(inc %) 1))
nums (map (fn [x] ,(Integer. (apply str x))) (permutations digits))]
(some (fn [x] (and (factor-9 x) x)) nums)))
([n]
(or
(= 1 (count (str n)))
(and (divisible-by-length n) (recur (quot n 10))))))
To my knowledge, TCO has a double benefit. The first one is that it does not use the stack as heavily as a non tail-recursive call and thus does not blow it on larger recursions. The second, I think is that consequently it's faster since it can be converted to a loop.
Now, I've made a very rough benchmark and have not seen any difference between the two implementations although. Am I wrong in my second assumption or does this have something to do with running on the JVM (which does not have automatic TCO) and recur using a trick to achieve it?
Thank you.
The use of recur does speed things up, but only by about 3 nanoseconds (really) over a recursive call. When things get that small they can be hidden in the noise of the rest of the test. I wrote four tests (link below) that are able to illustrate the difference in performance.
I'd also suggest using something like criterium when benchmarking. (Stack Overflow won't let me post with more than 1 link since I've got no reputation to speak of, so you'll have to google it, maybe "clojure criterium")
For formatting reasons, I've put the tests and results in this gist.
Briefly, to compare relatively, if the recursive test is 1, then the looping test is about 0.45, and the TCO tests about 0.87 and the absolute difference between the recursive and TCO tests are around 3ns.
Of course, all the caveats about benchmarking apply.
When optimizing any code, it's good to start from potential or actual bottlenecks and optimize that first.
It seems to me that this particular piece of code is eating most of your CPU time:
(map (fn [x] ,(Integer. (apply str x))) (permutations digits))
And that doesn't depend on TCO in any way - it is executed in same way. So, tail call in this particular example will allow you not to use up all the stack, but to achieve better performance, try optimizing this.
just a gentile reminder that clojure has no TCO
After evaluating factor-9 (quot n 10) an and and an or has to be evaluated before the function can return. Thus it is not tail-recursive.
Thanks a lot for all the beautiful answers! Cannot mark just one as correct
Note: Already a wiki
I am new to functional programming and while I can read simple functions in Functional programming, for e.g. computing the factorial of a number, I am finding it hard to read big functions.
Part of the reason is I think because of my inability to figure out the smaller blocks of code within a function definition and also partly because it is becoming difficult for me to match ( ) in code.
It would be great if someone could walk me through reading some code and give me some tips on how to quickly decipher some code.
Note: I can understand this code if I stare at it for 10 minutes, but I doubt if this same code had been written in Java, it would take me 10 minutes. So, I think to feel comfortable in Lisp style code, I must do it faster
Note: I know this is a subjective question. And I am not seeking any provably correct answer here. Just comments on how you go about reading this code, would be welcome and highly helpful
(defn concat
([] (lazy-seq nil))
([x] (lazy-seq x))
([x y]
(lazy-seq
(let [s (seq x)]
(if s
(if (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
y))))
([x y & zs]
(let [cat (fn cat [xys zs]
(lazy-seq
(let [xys (seq xys)]
(if xys
(if (chunked-seq? xys)
(chunk-cons (chunk-first xys)
(cat (chunk-rest xys) zs))
(cons (first xys) (cat (rest xys) zs)))
(when zs
(cat (first zs) (next zs)))))))]
(cat (concat x y) zs))))
I think concat is a bad example to try to understand. It's a core function and it's more low-level than code you would normally write yourself, because it strives to be efficient.
Another thing to keep in mind is that Clojure code is extremely dense compared to Java code. A little Clojure code does a lot of work. The same code in Java would not be 23 lines. It would likely be multiple classes and interfaces, a great many methods, lots of local temporary throw-away variables and awkward looping constructs and generally all kinds of boilerplate.
Some general tips though...
Try to ignore the parens most of the time. Use the indentation instead (as Nathan Sanders suggests). e.g.
(if s
(if (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
y))))
When I look at that my brain sees:
if foo
then if bar
then baz
else quux
else blarf
If you put your cursor on a paren and your text editor doesn't syntax-highlight the matching one, I suggest you find a new editor.
Sometimes it helps to read code inside-out. Clojure code tends to be deeply nested.
(let [xs (range 10)]
(reverse (map #(/ % 17) (filter (complement even?) xs))))
Bad: "So we start with numbers from 1 to 10. Then we're reversing the order of the mapping of the filtering of the complement of the wait I forgot what I'm talking about."
Good: "OK, so we're taking some xs. (complement even?) means the opposite of even, so "odd". So we're filtering some collection so only the odd numbers are left. Then we're dividing them all by 17. Then we're reversing the order of them. And the xs in question are 1 to 10, gotcha."
Sometimes it helps to do this explicitly. Take the intermediate results, throw them in a let and give them a name so you understand. The REPL is made for playing around like this. Execute the intermediate results and see what each step gives you.
(let [xs (range 10)
odd? (complement even?)
odd-xs (filter odd? xs)
odd-xs-over-17 (map #(/ % 17) odd-xs)
reversed-xs (reverse odd-xs-over-17)]
reversed-xs)
Soon you will be able to do this sort of thing mentally without effort.
Make liberal use of (doc). The usefulness of having documentation available right at the REPL can't be overstated. If you use clojure.contrib.repl-utils and have your .clj files on the classpath, you can do (source some-function) and see all the source code for it. You can do (show some-java-class) and see a description of all the methods in it. And so on.
Being able to read something quickly only comes with experience. Lisp is no harder to read than any other language. It just so happens that most languages look like C, and most programmers spend most of their time reading that, so it seems like C syntax is easier to read. Practice practice practice.
Lisp code, in particular, is even harder to read than other functional languages because of the regular syntax. Wojciech gives a good answer for improving your semantic understanding. Here is some help on syntax.
First, when reading code, don't worry about parentheses. Worry about indentation. The general rule is that things at the same indent level are related. So:
(if (chunked-seq? s)
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
(cons (first s) (concat (rest s) y)))
Second, if you can't fit everything on one line, indent the next line a small amount. This is almost always two spaces:
(defn concat
([] (lazy-seq nil)) ; these two fit
([x] (lazy-seq x)) ; so no wrapping
([x y] ; but here
(lazy-seq ; (lazy-seq indents two spaces
(let [s (seq x)] ; as does (let [s (seq x)]
Third, if multiple arguments to a function can't fit on a single line, line up the second, third, etc arguments underneath the first's starting parenthesis. Many macros have a similar rule with variations to allow the important parts to appear first.
; fits on one line
(chunk-cons (chunk-first s) (concat (chunk-rest s) y))
; has to wrap: line up (cat ...) underneath first ( of (chunk-first xys)
(chunk-cons (chunk-first xys)
(cat (chunk-rest xys) zs))
; if you write a C-for macro, put the first three arguments on one line
; then the rest indented two spaces
(c-for (i 0) (< i 100) (add1 i)
(side-effects!)
(side-effects!)
(get-your (side-effects!) here))
These rules help you find blocks within the code: if you see
(chunk-cons (chunk-first s)
Don't count parentheses! Check the next line:
(chunk-cons (chunk-first s)
(concat (chunk-rest s) y))
You know that the first line is not a complete expression because the next line is indented beneath it.
If you see the defn concat from above, you know you have three blocks, because there are three things on the same level. But everything below the third line is indented beneath it, so the rest belongs to that third block.
Here is a style guide for Scheme. I don't know Clojure, but most of the rules should be the same since none of the other Lisps vary much.
First remember that functional program consists of expressions, not statements. For example, form (if condition expr1 expr2) takes its 1st arg as a condition to test for the boolean falue, evaluates it, and if it eval'ed to true then it evaluates and returns expr1, otherwise evaluates and returns expr2. When every form returns an expression some of usual syntax constructs like THEN or ELSE keywords may just disappear. Note that here if itself evaluates to an expression as well.
Now about the evaluation: In Clojure (and other Lisps) most forms you encounter are function calls of the form (f a1 a2 ...), where all arguments to f are evaluated before actual function call; but forms can be also macros or special forms which don't evaluate some (or all) of its arguments. If in doubt, consult the documentation (doc f) or just check in REPL:
user=> apply
#<core$apply__3243 clojure.core$apply__3243#19bb5c09> a function
user=> doseq
java.lang.Exception: Can't take value of a macro: #'clojure.core/doseq a macro.
These two rules:
we have expressions, not statements
evaluation of a subform may occur or not, depending of how outer form behaves
should ease your groking of Lisp programs, esp. if they have nice indentation like the example you gave.
Hope this helps.