Rules Engine or Event Collaboration

January 9, 2009

Models of Computation

Some examples of models of computation include General Recursive Functions, Turing Machines, Lambda Calculus, Finite State Machines, and Production Systems. These are only some models of computation.

Martin Fowler has a pretty good post on rules engines (production system). “… providing an alternative computational model.”

Wikipedia’s definition is “A model of computation is the definition of the set of allowable operations used in computation and their respective costs.” I myself like the definition provided by “The Computational Beauty of Nature” [p27]. “… a model of computation describes how to build recipes or, if you like , a recipe for recipes.”

Both definitions seem to define two different things. The first definition describes programming languages. The second describes meta programming. These two definitions are not mutually exclusive. All programming languages have some form of meta programming. Just some languages have more powerful meta programming facilities.

In Common Lisp the most common way for the usage of meta programming is through the use of defmacro. Bill Clementson’s Blog post covers Joswig’s use of an embedded DSL in Lisp. Guess what allows him to make such a compact DSL? defmacro of course. Another nice Joswig post on comp.lang.lisp goes through an iterative cycle of design using defmacro.

Read the rest of this entry »

Object Programming in Lisp Observation #1

January 5, 2009

When developing with the object framework, I end up excreting all the side-effect-free (SEF) code from the object. Remember the reason for an object is to encapsulate state.

(defun format-results (result-totals)
  (destructuring-bind (result-totals asserts passes errors elapses) result-totals
     (format nil "~A Total Test(s)" result-totals)
     (format nil "~A Assertions" asserts)
     (format nil "~A Passes" passes)
     (format nil "~A Failures" (- asserts passes))
     (format nil "~A Errors" errors)
     (format nil "~,3F Second(s)" elapses))))

(defun result-sums (result-totals)
  (loop for (nil assert pass error elapse) in result-totals
        summing assert into asserts
        summing pass into passes
        summing error into errors
        summing elapse into elapses
         (list (length result-totals) asserts passes errors elapses))))

(defobj results-model
  (:members ((database nil)))
  (:methods ((:get-result-totals ()
                  (format-results (result-sums (retrieve-totals database))))

             (:connect-db (db)
               (setf database db))

             (:insert-result-data (result-data)
               (add-result database result-data))))

This method really it makes it easier to test the SEF functions. When using the object’s methods for interacting with state during tdd, you have to maintain a reference to the object. By excreting the functionality out of the object, you no longer need the reference. You just test for functionality.

    (assert-equal '("0 Total Test(s)" "0 Assertions" "0 Passes" "0 Failures" "0 Errors"
           "0.000 Second(s)") (format-results (list 0 0 0 0 0))))))

    (assert-equal '(1 0 0 0 0) (result-sums (list (list :no-name 0 0 0 0)))))

    (assert-equal '(2 1 1 1 0.15100001) (result-sums (list (list :t1 0 0 1 0.001) (list :t2 1 1 0 0.15)))))))

 (:setup ((db (make-database))
          (model (make-results-model)))
   (connect-db model db))
    (let ((totals '("0 Total Test(s)" "0 Assertions" "0 Passes" "0 Failures" "0 Errors"
           "0.000 Second(s)")))
      (assert-equal totals (get-result-totals model))))

    (let ((totals '("1 Total Test(s)" "1 Assertions" "1 Passes" "0 Failures" "0 Errors"
           "0.000 Second(s)")))
      (insert-result-data model (list :no-name 1 1 0 0.0))
      (assert-equal totals (get-result-totals model))))))

This is very conducive to programming incrementally.

The function we want to look at is get-result-totals. This function retrieve the totals from the database. We pass this then to result-sums. It’s results are then passed to format-results.

  1. Retrieve results from database.
  2. Sum results.
  3. Format results.

Happy January!

An Object in Lisp. Part 6

January 2, 2009

What a way to start a little update on the the object framework that I have been pushing on.

The last update talked about ‘destructuring-bind‘. I had an epipheny the other day when I was trying to tdd a way to create generic functions for the framework. That led me to throwing away the destructuring-bind.

In order to explain my reasoning we need to go back to the representation of an object in the framework. The representation is a list of closures referenced by properties.

(defun hello (obj &rest args)
  (apply (getf obj :hello) args)

(defvar hold1 (list :hello (lambda () (print 'hello))))
(defvar hold2 (list :hello (lambda (x) (print x))))

The above lists can be accessed with a getf that retrieves the lambda from the list. To execute the lambda just apply. The hello defun above will handle either list as obj.

Something that I now know,  is that the lambda does its own destructuring-bind on its parameter list.  So here is how I create the accessor function for all objects  (generic and multiple signatures):

(defmacro make-property (name)
  (let ((g (gensym)))
    (multiple-value-bind (sym-name key-name) (symbol-and-keyword name)
         (if (not (fboundp ',sym-name))
             (defun ,sym-name (obj &rest ,g)
               (block ,sym-name
                 (apply (getf obj ,key-name) ,g)))))))

Happy New Year!