syntax-rules problem

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

syntax-rules problem

Sascha Ziemann
I have the following macro.

(define-syntax define-facts
  (syntax-rules ()
    ((_ (name a0 a1 ...) ((v00 v01 ...) (v10 v11 ...) ...))
     '(define (name a0 a1 ...)
        (conde
          ((== a0 v00) (== a1 v01) ...)
          ((== a0 v10) (== a1 v11) ...)
          ...)))))

Some Schemes like Guile, Chez, MIT and Ikarus succeed to evaluate the
following expression.

(define-facts (fathero f c)
  (("Abraham" "Ismael")
   ("Abraham" "Isaac")
   ("Isaac"   "Jacob")
   ("Jacob"   "Benjamin")))

=>

(define (fathero f c)
  (conde
    ((== f "Abraham") (== c "Ismael"))
    ((== f "Abraham") (== c "Isaac"))
    ((== f "Isaac") (== c "Jacob"))
    ((== f "Jacob") (== c "Benjamin"))))

But some fail. Kawa fails with an exception:

/dev/stdin:9:1: evaluating syntax transformer 'define-facts' threw
java.lang.ArrayIndexOutOfBoundsException: 1

I am still not sure, if it is a bug or if this is another undefined
part of Scheme.

Is it a bug?
Reply | Threaded
Open this post in threaded view
|

Re: syntax-rules problem

Per Bothner
On 03/10/2017 01:35 AM, Sascha Ziemann wrote:

> I have the following macro.
>
> (define-syntax define-facts
>   (syntax-rules ()
>     ((_ (name a0 a1 ...) ((v00 v01 ...) (v10 v11 ...) ...))
>      '(define (name a0 a1 ...)
>         (conde
>           ((== a0 v00) (== a1 v01) ...)
>           ((== a0 v10) (== a1 v11) ...)
>           ...)))))

This got mangled a bit, but definition is clearly wrong.
I cleaned it up:

(define-syntax define-facts
   (syntax-rules ()
     ((_ (name arg ...) ((value key ...) ...))
      (define (name arg ...)
        (cond
         ((and (equal? arg key) ...) value)
         ...)))))

However, this is still not valid R7RS Scheme:

     Pattern variables that occur in subpatterns followed by one or more
     instances of the identifier h<ellipsis> are allowed only in subtemplates
     that are followed by as many instances of <ellipsis>.

The problem is that arg is singly-nested in the pattern, but
doubly-nested in the template.

Kawa does support an extension for different nesting levels, meant to support
things like (x (y ...) ...)  => (((x y) ...) ...).  However, in that case the x
varies by the outer "index":
((x0 (y00 y01)) (x1 (y10 y11 y12)))
  ==> (((x0 y00) (x0 y01)) ((x1 y10) (x1 y11) (x1 y12)))
But for define-facts the single-nested arg needs to vary with the
*inner* index. I.e. you would need Kawa to expand the example to:
  ==> (((x0 y00) (x1 y01)) ((x0 y10) (x1 y11) (x2 y12))) ; Oops no x2
But Kawa doesn't do that.

A solution that does work uses a list:

(define-syntax define-facts
   (syntax-rules ()
     ((_ name ((value . keys) ...))
      (define (name . args)
        (cond ((equal? args 'keys) value) ...)))))

(define-facts father-of
   (("Abraham" "Ismael")
    ("Abraham" "Isaac")
    ("Isaac"   "Jacob")
    ("Jacob"   "Benjamin")))

Obviously, Kawa should not throw ArrayIndexOutOfBoundsException,
but should instead report an error. So that is a Kawa bug.
--
        --Per Bothner
[hidden email]   http://per.bothner.com/
Reply | Threaded
Open this post in threaded view
|

Re: syntax-rules problem

Per Bothner
On 03/10/2017 11:04 AM, Per Bothner wrote:
> Obviously, Kawa should not throw ArrayIndexOutOfBoundsException,
> but should instead report an error. So that is a Kawa bug.

I fixed Kawa to print an error message in this case, rather than
throwing ArrayIndexOutOfBoundsException.

The message isn't as helpful as I'd like. One complication is that
pattern variable names aren't available at macro-expansion time.
This could be changed, but it isn't a priority right now.
--
        --Per Bothner
[hidden email]   http://per.bothner.com/