|
From: Ken A. <kan...@bb...> - 2004-10-29 21:17:12
|
{
One of the nice things Scheme is good for is writing embedded
minilangauges. You can write a lot less code if you tailor such
languages for your application.
For example, since you main a triathlon sight a common idiom might be
to do a database lookup and generate HTML.
Here's one way to do it, there are many others. Also, i cut some corners.
There is a lot going on in this example, so its OK if you don't
understand it right a way.
}
(load "elf/jdbc.scm")
(load "elf/html-gen.scm")
(java.sql.DriverManager.registerDriver (oracle.jdbc.driver.OracleDriver.))
;;; dbConnection: -> java.sql.Connection
(define (dbConnection)
(DriverManager.getConnection dbUrl dbUser dbPassword))
;;; withDbConnection: Connection thunk -> Object
(define (withDbConnection con action)
;; Action is a procedure with a Connection argument.
;; The connection is closed when this returns.
(tryCatch
(Procedure.tryFinally (lambda () (action con))
(lambda () (.close con)))
(lambda (e) (print e)(.close con))))
{
Here is a simple macro. I use collect-query for simplicity.
}
(define-macro (mapQuery con query args . body)
`(withDbConnection
,con
(let ((f (lambda ,args ,@body)))
(lambda (con)
(map (lambda (row) (apply f (array->list row)))
(cdr (collect-query con ,query)))))))
{
Here's an example of using the macro. It uses the <> macro for
generating HTML. So we're mixing Scheme, JScheme's quasi-string and 2
embedded languages here. While this example doesn't show it,
<> also uses quasquote so there is 1 language (scheme) and 4 sublanguages used here.
This sounds pretty complicated, but our experience is that it has
worked pretty well.
}
(define (runwayData icao)
(<> p {Airport [icao] has runways:}
(<> table
(<> tr (<> td "High") (<> td "Low") (<> td "Length"))
(mapQuery
(dbConnection)
{select r.high_ident, r.low_ident, r.length
from runway r, airport a
where r.arpt_ident = a.arpt_ident and a.icao = '[icao]'}
(high low length)
(<> tr (<> td high) (<> td low) (<> td length))))))
{
If you wanted a cascade of transformations and were willing to use
scheme s-expressions as an intermediate representation, this would
even be simpler.
}
(define (runwayData icao)
`(airport
(icao ,icao)
,@(mapQuery
(dbConnection)
{select r.high_ident, r.low_ident, r.length
from runway r, airport a
where r.arpt_ident = a.arpt_ident and a.icao = '[icao]'}
(high low length)
(runway (highend ,high) (lowend ,low) (length ,length)))))
|