Thanks for the snippet Nicolas but that is not the problem! I do know
how to implement the 'undo' functionality...In OOP this is called the
"Command" design pattern...The command interface has execute(from, to)
and undo(from,to) (which calls execute with reversed arguments)...That
part is not hard at all...the problem arises when trying to manage all
this state (as you indicated)....also since I 'm using reducers quite
heavily, it is not easy to isolate mutation on 1 thread (it also seems
impossible to do any pruning)... I would have to revert to single
threaded execution in order to implement all this...
Jim
btw, my functional approach of undoing was simply to log every new board
change in a vector via watches and atom. This way not only I can undo
without calling 'move' but I can also serialize the entire history and
have it available when you load the game back in! pretty cool and simple
I think...
On 26/08/12 15:56, nicolas.o...@gmail.com wrote:
1. Gary Bernhardt has been playing with a "new" approach he calls
"Functional Core, Imperative Shell". Essentially, it's another take on
the question of how to limit the scope of mutation in order to get the
most out of the correctness of mutation-free algorithms and the
performance of mutating data instead of replicating it.
It seems to be this treats of another question: how to have IO in a
functional world.
And it gives the classic answer: write the functional core and wrap s
small IO shell around.
Jim is asking another question: what if you can't get good enough
performance in a given algorithm
with persistent functional data structures.
My views is that state is difficult. Every state makes your program
harder to maintain and less modular.
However, a localised state to a function or a group of functions is
perfectly fine.
In the case of your checkers problem, you can encapsulate in a
protocol the notion of being an undoable move:
(defprotocol UndoableMove
(move [this b] "return the board or nil if it can't be applied")
(undo [this b] "returns the board. Fails if it cannot be undone"))
Then create a protocol for boards:
(defprotocol BoardLike
(apply-move [b m] "Apply move m. Keep it in undo stack. Returns a board.")
(undo-last-move [b] "Undo last move if any, else fails. Return a board"))
(Note: I like better threading the board, even if it is updated in place.
It offers more flexibility: you can use persistent/transient or
mutable data-structures.
You can also decide to change representation of the board, if you want.)
What is essential though, is that if I use that to explore the game
tree, I would NOT use it
to represent the state of the game in rest of the program. Too many
way to stumble later.
I would convert the board into the mutable representation, and the
explore the game tree.
And copy back into an immutable board once done.
Transients are a good way to do this.
But the key is mutable state works for me for mono-thread, small localised code.
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en