From: "M. Edward (Ed) Borasky" Date: 2006-09-23T11:01:53+09:00 Subject: Re: [QUIZ] Code to S-Exp (#95) Ruby Quiz wrote: > The three rules of Ruby Quiz: > > 1. Please do not post any solutions or spoiler discussion for this quiz until > 48 hours have passed from the time on this message. > > 2. Support Ruby Quiz by submitting ideas as often as you can: > > http://www.rubyquiz.com/ > > 3. Enjoy! > > Suggestion: A [QUIZ] in the subject of emails about the problem helps everyone > on Ruby Talk follow the discussion. Please reply to the original quiz message, > if you can. > > -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= > > by Ken Bloom > > S-expressions are a useful way of representing functional expressions in many > aspects of computing. Lisp's syntax is based heavily on s-expressions, and the > fact that Lisp uses them to represent both code and data allows many interesting > libraries (such as CLSQL: http://clsql.b9.com/) which do things with functions > besides simply evaluating them. While working on building a SQL generation > library, I found that it would be nice to be able to generate s-expressions > programmatically with Ruby. > > An s-expression is a nested list structure where the first element of each list > is the name of the function to be called, and the remaining elements of the list > are the arguments to that function. (Binary operators are converted to prefix > notation). For example the s-expression (in LISP syntax) > > (max (count field)) > > would correspond to > > max(count(field)) > > in ordinary functional notation. Likewise, > > (roots x (+ (+ (* x x) x) 1 )) > > would correspond to > > roots(x, ((x*x) + x) + 1) > > since we treat binary operators by converting them to prefix notation. > > Your mission: Create a function named sxp() that can take a block (not a > string), and create an s-expression representing the code in the block. > > Since my goal is to post-process the s-expressions to create SQL code, there is > some special behavior that I will allow to make this easier. If your code > evaluates (rather than parsing) purely numerical expressions that don't contain > functions or field names (represented by Symbols here), then this is > satisfactory behavior since it shouldn't matter whether Ruby evaluates them or > the SQL database evaluates them. This means, for example, that sxp{3+5} can give > you 8 as an s-expression, but for extra credit, try to eliminate this behavior > as well and return [:+, 3, 5]. > > It is very important to avoid breaking the normal semantics of Ruby when used > outside of a code block being passed to sxp. > > Here are some examples and their expected result: > > sxp{max(count(:name))} => [:max, [:count, :name]] > sxp{count(3+7)} => [:count, 10] or [:count, [:+, 3, 7]] > sxp{3+:symbol} => [:+, 3, :symbol] > sxp{3+count(:field)} => [:+, 3, [:count, :field]] > sxp{7/:field} => [:/, 7, :field] > sxp{:field > 5} => [:>, :field, 5] > sxp{8} => 8 > sxp{:field1 == :field2} => [:==, :field1, :field2] > 7/:field => throws TypeError > 7+count(:field) => throws NoMethodError > 5+6 => 11 > :field > 5 => throws NoMethodError > > (In code for this concept, I returned my s-expression as an object which had > inspect() modified to appear as an array. You may return any convenient object > representation of an s-expression.) > > Could you write some more tests? :)