Arc Forumnew | comments | leaders | submitlogin
1 point by thaddeus 4834 days ago | link | parent

OK, I changed the blog and the code. :) I think I was just adding too much unnecessary complexity.


2 points by rocketnia 4834 days ago | link

I like both approaches. ^_^ I even think you may not have gone far enough with the complicated one. It would be pretty fascinating to make an s-expression DSL for this. From http://fleetdb.org/docs/queries/select.html, there's the list of "where" expression types:

  ["=",      <attribute>, <value>]
  ["!=",     <attribute>, <value>]
  ["<",      <attribute>, <value>]
  ["<=",     <attribute>, <value>]
  [">",      <attribute>, <value>]
  [">=",     <attribute>, <value>]
  ["in",     <attribute>, [<value>+]]
  ["not-in", <attribute>, [<value>+]]
  ["><",     <attribute>, [<low-value>, <high-value>]]
  [">=<",    <attribute>, [<low-value>, <high-value>]]
  ["><=",    <attribute>, [<low-value>, <high-value>]]
  [">=<=",   <attribute>, [<low-value>, <high-value>]]
  ["or",     <where-condition>+]
  ["and",    <where-condition>+]
It should be possible to add a "no" macro to the DSL, which compiles

  (no ("=" a b))           to ("!=" a b),
  (no ("in" a x y z))      to ("not-in" a x y z),
  (no (">=<=" a min max))  to (or ("<" a min) (">" a max)),
  and so forth.
We should also be able to abstract away operators like ">=<=" into more Arc-ish formats:

     (<= 100 "foo" 200)
  to (and (<= 100 "foo") (<= "foo" 200))
  to (and (">=" "foo" 100) ("<=" "foo" 200))
  to (">=<=" "foo" 100 200)
This should probably evolve into a more complicated system than normal Arc macros; there'd probably be a need to collapse things like (and (and ...) ...) so that subexpressions can be combined into their ">=<=" forms.

I know "more complicated" probably isn't everyone's thing, but I think it'll be a good way for me to practice some code generation techniques one of these days, unless someone beats me to it. ^_^

-----

1 point by thaddeus 4833 days ago | link

Thanks,

Your ideas would be ideal, though probably beyond my current skill set. I tried fiddling around with the original macro's, but I then started finding more problems than I was solving. So I changed it to be a dumb client version, just to make sure that if any newb (like me) started using the code, they would at least not get tripped up by all the bugs.

Any work you can contribute, even as a starting point, would be great and no doubt will prove educating to me.

-----

2 points by rocketnia 4832 days ago | link

The ideas were a bit more complicated than I knew how to break down into a quick running example. XD;; That's kinda why I just brain-dumped them into that post.

As a basic outline of the technique, imagine building a library of simple functions that construct FleetDB queries (which is to say, a combinator library), and then building macros on top of those to make them a bit nicer to use. That's most of what I'd do, except that I'd probably put in two extra abstraction layers:

- A translator for optimizing queries just before they're sent to FleetDB. This may or may not turn out to be helpful, depending on whether FleetDB does its own optimization. Also, this is a bit of a computational complexity rabbit hole, and I'm not sure how I'd begin to approach it. I'd probably just make it extensible so other people could try. :)

- A macro that takes an s-expression DSL and manually walks over it and converts it into calls to the combinator library. This would allow us to use operator names like 'or and '< without redefining Arc's own 'or and '<. This is probably where I can best help you out with a code example:

  (= dsl-macs* (table))
  
  (mac dsl-mac (name parms . body)
    `(= (dsl-macs* ',name) (fn ,parms ,@body)))
  
  (def expand-dsl (expr)
    (if atom.expr
      expr
      (let (op . args) expr
        (aif dsl-macs*.op
          (apply it args)
          expr))))
  
  (mac dsl (expr)
    expand-dsl.expr)
  
  
  ; FleetDB combinator
  (def fleetdb-or args
    (cons "or" args))
  
  ; FleetDB DSL extension using that combinator
  (dsl-mac or args
    `(fleetdb-or ,@(map expand-dsl args)))
Thanks to http://tryarc.org/, this is working code. :)

  arc> (dsl:or '("<" "foo" 1) (or '("=" "bar" "woof") '(">" "foo" 11))))
  ("or" ("<" "foo" 1) ("or" ("=" "bar" "woof") (">" "foo" 11)))
I've also posted this code to https://gist.github.com/808357 for posterity. ^_^

-----