nklein wrote:Somewhere, there will be a list of who is currently logged in. Say, for sake of argument that this list should be kept in alphabetical order by nickname.
For this, I canibalized (ported) the dataset structure from haskell. It is nothing more than a binary tree. So I would have code like this :
- Code: Select all
(setf users (dataset-insert new-user users))
As this is a persistent datastructure, the old version still exists (neat for undo), and could be use in an other thread at the same time(say to write the state to a file or something).
nklein wrote:The situation gets worse if someone can update their nickname in real time.
You would need some kind of a function or macro that will do the copying for you. here is the one i use :
- Code: Select all
(defmacro with-update ((type-name instance) &body updates)
(let ((rectype (find-class type-name)))
(unless rectype
(error "Class ~a was not found." type-name))
(let ((instance-gensym (gensym "INSTANCE-")))
(let ((struct-slots (structure:structure-class-slot-names rectype)))
(loop for (name . nil) in updates
unless (member name struct-slots)
do (error (error "Slot ~a not a member of class ~a." name type-name)))
`(let ((,instance-gensym ,instance))
(,(find-symbol (concatenate 'string "MAKE-" (symbol-name type-name)) (symbol-package type-name))
,@(loop for slot in struct-slots
for assoc = (assoc slot updates)
if assoc collect (second assoc)
else collect `(,(slot-name type-name slot) ,instance-gensym))))))))
It is somewhat cumbersome to use and works under the assumtion that the make-record function doesn't require keyword arguments (it's all positional here). Also that's for lispworks only.
an example usage :
- Code: Select all
(defun dataset-delete (value dataset)
(let-rec-slots ((dataset dataset (compare-func key-func root-node)))
(with-update (dataset dataset)
(root-node (%delete value compare-func key-func root-node)))))
Then you have the problem of updating something deep in the your "object hierachy".
I was asking that question on the haskell mailing list a few months ago. And they were kind enough to introduce me to the concept of "lifting".
It works something like this (dataset-lift "Sacha" users (lambda (user) (with-update (user user) (password "bigsecret"))))
dataset-lift will find user "Sacha" then updates it's password (so it creates a new user) and then creates the log2 nodes up to the top and returns a new dataset, thus hiding the details of the operations.
or deeper : (lift 'users config (dataset-lift "Sacha" users (lambda (user) (with-update (user user) (name "Pedro")))))
lift does the same as dataset-lift for the simpler case of updating a slot in a record.
Hope this helps
Sacha