Re-thinking Python through Lisp

Occasionally when I'm feeling the need to tune up my software development skills. I'll venture off in to unfamiliar territory in hopes that I can pick up a few things that I can use later on.

Lisp has always been an elusive language for me. I can appreciate how cool it is to those who are fans of it, yet I have not gotten to the point where I'm productive in it. Nonetheless, occasionally I will try to make it through a tutorial, hoping to get a better understanding of it.There's a decent book online for it and this chapter is a mind bender(for me anyway)
Practical Common Lisp: A Simple Database

Mainly because it shows you what's cool about lisp. Which is the macro functionality which allows you to easily(relatively) create your own Domain Specific Languages(DSL's)

In that chapter they step you through a SQL like db example where you query your data store like so,

(select (where :title "Over Kill" :ripped t))

So after about a year of trying and failing , I went back and tried to get through it again. And got hung up in the same place, basically the macro facilities kill me,, and the parens don't help me at all but I figured eventually I could see through them or learn to like them maybe.

No dice, so I went about trying to identify what exactly it is that keeps me coming back to Lisp. Is it really the macros? Or the purely functional coding style?

So I decided to try an experiment and go through that chapter and see how far I would get writing it in python. Because I know python, and I suspected, where the Lisp solution is a macro I would hit the brick wall in Python thus coming to the conclusion that, the macro facility is what I want.

Interestingly enough I was able to implement everything in that chapter, in a relatively quot;pythonic" way.

the python version of the sql-ish dsl looks like this...

select(where(artist='Over Kill',ripped=True))

Here's the lisp version

;;DSL Query Routines
(defun make-comparison-expr (field value)
`(equal (getf cd ,field) ,value)
)
(defun make-comparisons-list (fields)
(loop while fields
collecting (make-comparison-expr (pop fields) (pop fields))
)
)
(defmacro where (&rest clauses)
`#'(lambda (cd) (and ,@(make-comparisons-list clauses))
))
(defun select (selector-fn)
(remove-if-not selector-fn *db*)
)

Here's the python implementation. Basically wherever a macro would likely be the answer in lisp, the function factory pattern in python will suffice.

#data query langauge
 
def select(selector_fn):
  global db
  return filter(selector_fn, db)
 
def make_comp_expr(field,value):
  def x(rec):
    if rec.has_key(field):
      return rec[field]==value
    else:
      return False
  return x
 
def where(**kw):
  exps = []
  for k,v in kw.items():
    exps.append(make_comp_expr(k,v))
 
  def wrec(rec):
    return reduce(lambda x,y: x and y, map(lambda x: x(rec),exps))
  return wrec

So I was pretty happy that I was able to implement it somewhat, The trick doesn't seem to be to write code that writes code for you via a macro system after all, though I'm sure that there is a place for macros are the only solution. But just as I fear the black magic voodoo that goes on in so many libraries I often have to interact with, I surely do not trust myself with that kind of power to introduce my own voodoo.

Getting a handle on using map, reduce and filter will probably prove to be very useful in the future for me though.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd><p> <h1><h2><h3><h4><h5><h6> <img>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • E-Mail addresses are hidden with reCAPTCHA Mailhide.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.