; Evaluating file: day2.clj
;
; Error printing return value (ClassCastException) at day2/parse-input (day2.clj:18).
; class clojure.lang.Atom cannot be cast to class clojure.lang.IFn (clojure.lang.Atom and clojure.lang.IFn are in unnamed module of loader 'app')
; Evaluation of file day2.clj failed: class clojure.lang.ExceptionInfo
clj꞉day2꞉>
what did I do wrong and how to solve this ?
and how can I return the position atom ??
It also looks like the branches in your cond are trying to mutate the state of the atom, but they would not do that at all, they would simply return a series of numerical values. If you do want to solve this like you would in an imperative language, you need to use swap! inside your cond, combined with update to identify which keyword in your position atom you are trying to change. That could make this approach work, although you should then use doseq instead of map since you are traversing the data for the purpose of causing side effects, rather than trying to apply pure functions and gather the result, so map would not even do anything until you consume the results.
I agree with kolme, however, that you would be better off figuring out how to solve this without an atom and without mutation. As a hint, how could you use reduce combined with the position and the list of instructions, to yield an updated position?
; class java.lang.String cannot be cast to class java.lang.Number (java.lang.String and java.lang.Number are in module java.base of loader 'bootstrap')
You seem to have missed my response above that explains that you are not mutating the atom, which seems to be what you are trying to do, and which encourages you to study how you could use reduce to avoid needing an atom or mutation at all. (Even in that more idiomatic approach, you would still be using update to derive the new position information from the current position and direction, but you would simply be returning a new position to use as the result, rather than mutating anything.)
What your code does is look up a value from the position, and perform some arithmetic on it, and return the result. It does not change the atom in any way.
Sounds good! To help point you more clearly in the directions I was trying to get at in my response: study how update can be used to get an entire new position value by applying a function to a key within the current position value. Then, to continue along the approach you started with, study how you can combine swap! with that update invocation, to actually change the atom (and then replace your use of map with doseq, so that your code actually runs: it won’t as things currently stand, because you never consume the value returned by your thread-last macro, and map is lazy, and should only be used with pure functions and when the value of map will actually be consumed).
Once you are ready to take a more Clojure-like approach, look at how you can eliminate the atom entirely and use that update invocation along with reduce (instead of doseq) to combine the position value with the series of move instructions to return the final location, without mutating anytying.
Yes, you need to get to the point where you do understand that. For one thing, get rid of the parentheses around the + expression, and around (@position :horizontal), and get rid of the @. swap! takes an atom, a function, and its arguments. update is the function we want to use, and it is called with the old value of the atom, and takes a key that you want to compute a new value for, the function you want to call with that old value, and any additional arguments you want to give that function. So at a quick glance it would be closer to this:
(= first "forward")
(swap! position update :horizontal + (parse-long second))
(Also, that 5 absolutely doesn’t belong in there.)
Oops, sorry, didn’t notice until my edit that you were missing the update call. So update is the function we pass to swap!. It takes one version of the atom, and builds the other from it. I need to make a bit more of an edit to my explanation above to reflect that now.
All right, my explanation is fixed now. I would recommend working through some examples of how to effectively use swap! and update. They are fundamental to building mutations of data structures in Clojure. And then, when you are happy with this approach, it is also very much worth learning how to do without the atom entirely, and use update within reduce to step towards the answer without any mutable state.