Thursday, September 15, 2005
An analogy - Lisp as Graffiti
The Palm kind, that is.
Whining about Lisp's syntax is a favorite sport on the blogs, especially among students that have a Lisp assignment in a class. I look at it the same way Jeff Hawkins looked at Grafitti when developing the Palm (from a Fast Company article):
"People are smarter than appliances," Hawkins told his colleagues. "They can learn.'' He recalled a lesson from his Berkeley days: "People like learning. People can learn to work with tools. Computers are tools. People like to learn how to use things that work."
It's good to make things easy for the user, but there comes a point where if the user can compromise a little in one area they can gain a lot in others. For the original Palm, learning Graffiti meant the PDA could fit in your pocket, be cheap and run on two AAA's since the software could be simplified enough to fit in the restrictions of the machine. For Lisp, making a small change, going to prefix notation and "all those parentheses" gains you code as data as code, macros that match the syntax of the language, and everything else you've been reading about.
If you're a whiny student who doesn't want to believe me, try believing Robert Floyd, from his Turing Prize lecture (from here via here):
“Contact with the programming written under alien conventions may help. Visiting MIT on sabbatical this year, I have seen numerous examples of the programming power which Lisp programmers obtain from having a single data structure, which is also used as a uniform syntactic structure for all the functions and operations which appear in programs, with the capability to manipulate programs as data. Although my own previous enthusiasm has been for syntactically rich languages like the Algol family, I see now clearly and concretely the force of Minsky’s 1970 Turing Lecture, in which he argued that Lisp’s uniformity of structure and power of self-reference gave the programmer capabilities whose content was well worth the sacrifice of visual form.”
Whining about Lisp's syntax is a favorite sport on the blogs, especially among students that have a Lisp assignment in a class. I look at it the same way Jeff Hawkins looked at Grafitti when developing the Palm (from a Fast Company article):
"People are smarter than appliances," Hawkins told his colleagues. "They can learn.'' He recalled a lesson from his Berkeley days: "People like learning. People can learn to work with tools. Computers are tools. People like to learn how to use things that work."
It's good to make things easy for the user, but there comes a point where if the user can compromise a little in one area they can gain a lot in others. For the original Palm, learning Graffiti meant the PDA could fit in your pocket, be cheap and run on two AAA's since the software could be simplified enough to fit in the restrictions of the machine. For Lisp, making a small change, going to prefix notation and "all those parentheses" gains you code as data as code, macros that match the syntax of the language, and everything else you've been reading about.
If you're a whiny student who doesn't want to believe me, try believing Robert Floyd, from his Turing Prize lecture (from here via here):
“Contact with the programming written under alien conventions may help. Visiting MIT on sabbatical this year, I have seen numerous examples of the programming power which Lisp programmers obtain from having a single data structure, which is also used as a uniform syntactic structure for all the functions and operations which appear in programs, with the capability to manipulate programs as data. Although my own previous enthusiasm has been for syntactically rich languages like the Algol family, I see now clearly and concretely the force of Minsky’s 1970 Turing Lecture, in which he argued that Lisp’s uniformity of structure and power of self-reference gave the programmer capabilities whose content was well worth the sacrifice of visual form.”
Sunday, September 04, 2005
Fuzzy Queries on top of CLSQL
I originally planned to incorporate Fuzzy SQL more into CLSQL, but I don't think it's necessary for my purposes. With CLSQL's def-view-class extension of CLOS I can use generic methods, and it will look like the rest of the class. Later in the book I'm using, Fuzzy Modeling and Genetic Algorithms for Data Mining and Exploration there's a chapter on Genetic Tuning of Fuzzy Models, which I think will work better with external functions and methods as opposed to MOP or macro-based solutions inside CLSQL. Besides, I couldn't even get db-reader to work with my classes, so I'll just leave well enough alone.
This will be based on my previous big and tall entry. My data setup is
and I have a corresponding CLSQL view-class
The key is each class will have a qcix (query compatibility index) method that will be the overall membership function, doing some combination of individual membership functions of individual columns in the database. For our "big and tall" prospects we'll have a tall method for membership based on height, and a heavy method for membership based on weight. These functions will return a value from 0.0 to 1.0, with a linear scale from the 0 cutoff to the 1 cutoff. For overall membership we'll average the two other membership function.
So far, so good. Now we want to select only some records that have a qcix over a particular threshold. We can use CLSQL's addition to loop:
Oops! Perhaps another reason not to delve into the innards of CLSQL. Plan B:
So, starting with a CLSQL def-view-class we can externally add generic methods to support fuzzy queries.
This will be based on my previous big and tall entry. My data setup is
rrc=# select * from btprospects;
name | height | weight | age
----------+--------+--------+-----
Saunders | 74 | 215 | 52
Cassey | 73 | 188 | 40
Miller | 71 | 157 | 25
Freeman | 70 | 202 | 34
OMalley | 65 | 163 | 48
Jackson | 63 | 170 | 38
and I have a corresponding CLSQL view-class
(clsql:def-view-class btprospects ()
((name :db-kind :key
:type (string 20)
:initarg :name
:accessor name)
(height :type integer
:initarg :height
:accessor height)
(weight :type integer
:initarg :weight
:accessor weight)
(age :type integer
:initarg :age
:accessor age)))
The key is each class will have a qcix (query compatibility index) method that will be the overall membership function, doing some combination of individual membership functions of individual columns in the database. For our "big and tall" prospects we'll have a tall method for membership based on height, and a heavy method for membership based on weight. These functions will return a value from 0.0 to 1.0, with a linear scale from the 0 cutoff to the 1 cutoff. For overall membership we'll average the two other membership function.
(defmethod tall ((prospect btprospects))
(let ((raw-height (slot-value prospect 'height)))
(cond ((<= raw-height 54) 0.0)
((>= raw-height 72) 1.0)
(t (float (/ (- raw-height 54) (- 72 54)))))))
(defmethod heavy ((prospect btprospects))
(let ((raw-weight (slot-value prospect 'weight)))
(cond ((<= raw-weight 182) 0.0)
((>= raw-weight 220) 1.0)
(t (float (/ (- raw-weight 182) (- 220 182)))))))
(defmethod qcix ((prospect btprospects))
(float (/ (+ (tall prospect) (heavy prospect)) 2)))
CL-USER> (clsql:map-query 'list #'tall [clsql:select 'btprospects])
(1.0 1.0 0.9444444 0.8888889 0.6111111 0.5)
CL-USER> (clsql:map-query 'list #'heavy [clsql:select 'btprospects])
(0.8684211 0.15789473 0.0 0.5263158 0.0 0.0)
CL-USER> (clsql:map-query 'list #'qcix [clsql:select 'btprospects])
(0.93421054 0.57894737 0.4722222 0.7076024 0.30555555 0.25)
So far, so good. Now we want to select only some records that have a qcix over a particular threshold. We can use CLSQL's addition to loop:
(defun fuzzy-select (class-name cutoff)
(loop for (rec) being the records in (clsql:select class-name)
when (> (qcix rec) cutoff) collect rec))
CL-USER> (fuzzy-select 'btprospects 0.5)
; Warning: database-query-result-set not implemented for database type POSTGRESQL-SOCKET.
; While executing: #
Oops! Perhaps another reason not to delve into the innards of CLSQL. Plan B:
(defun fuzzy-select (class-name cutoff)
(let ((result '()))
(clsql:do-query ((rec) [clsql:select class-name])
(when (>= (qcix rec) cutoff)
(push rec result)))
result))
CL-USER> (mapcar #'name (fuzzy-select 'btprospects .5))
("Freeman" "Cassey" "Saunders")
So, starting with a CLSQL def-view-class we can externally add generic methods to support fuzzy queries.
Thursday, September 01, 2005
This wasn't even funny the first time (search friendly languages)
Occaisionally I want to see what other bloggers are doing with Lisp, so I use Technorati to search on Lisp. Every time, over the course of months now, I see at least once or twice a search page "Whose idea was it to put an "S" in the word "lisp"? ". And of course each time they act like they were the first to hear of it.
Never mind the AI Winter reasons, Lisp, Scheme and Arc need better names for searching purposes. This kind of thing never happens to Ocaml or Nemerle.
Never mind the AI Winter reasons, Lisp, Scheme and Arc need better names for searching purposes. This kind of thing never happens to Ocaml or Nemerle.