|
question on the opaque syntax object debate
Andrew Wilcox
(18 Aug 2005 15:58 UTC)
|
|
Re: question on the opaque syntax object debate
Andre van Tonder
(18 Aug 2005 16:59 UTC)
|
|
Re: question on the opaque syntax object debate Jens Axel Søgaard (21 Aug 2005 10:16 UTC)
|
|
Re: question on the opaque syntax object debate
Michael Sperber
(20 Aug 2005 06:50 UTC)
|
|
Re: question on the opaque syntax object debate
Matthias Neubauer
(20 Aug 2005 13:19 UTC)
|
|
Re: question on the opaque syntax object debate
bear
(20 Aug 2005 19:24 UTC)
|
|
Re: question on the opaque syntax object debate
Andre van Tonder
(20 Aug 2005 19:48 UTC)
|
|
Re: question on the opaque syntax object debate
Michael Sperber
(21 Aug 2005 09:50 UTC)
|
|
Re: question on the opaque syntax object debate
bear
(21 Aug 2005 12:31 UTC)
|
|
Re: question on the opaque syntax object debate
Panu Kalliokoski
(21 Aug 2005 14:14 UTC)
|
|
Re: question on the opaque syntax object debate
Michael Sperber
(22 Aug 2005 16:00 UTC)
|
Andre van Tonder wrote: > On Thu, 18 Aug 2005, Andrew Wilcox wrote: >> Thus my question is: does PLT Scheme have syntax location features >> that this SRFI proposal is not able to provide? > There is one that it would in principle be able to provide but chooses > not to: The SRFI proposal requires the first argument of > datum->syntax-object to be an identifier, as indeed Chez does, while PLT > allows an arbitrary syntax object there. > > There is no fundamental reason why this cannot be supported, but it > would make the reference implementation more complex. Also, I don't > know how useful this feature really is in practice. Attached below is an example, in which I used it. The function substitute-<>-with-name makes a recursive decent on a syntax-object and replaces <> with fresh names. Quasisyntax/loc (which is implemented using datum->syntax-object) is used to keep the properties of the original syntax. /Jens Axel
;;; deep-cut.ss -- Jens Axel Soegaard
; This file implementes a generalized version of cut from srfi-26.
; The macro cut transforms a <cut-expression> into a <lambda expression>
; with as many formal variables as there are slots in the list <slot-or-expr>*.
; The body of the resulting <lambda expression> calls the first <slot-or-expr>
; with arguments from <slot-or-expr>* in the order they appear. In case there
; is a rest-slot symbol, the resulting procedure is also of variable arity,
; and the body calls the first <slot-or-expr> with all arguments provided to
; the actual call of the specialized procedure.
; <cut-expression> --> (cut <slot-or-expr> <slot-or-expr>*)
; | (cut <slot-or-expr> <slot-or-expr>* <...>) ; with "rest-slot"
; | (cute <slot-or-expr> <slot-or-expr>*) ; evaluate non-slots at specialization time
; | (cute <slot-or-expr> <slot-or-expr>* <...>) ; with "rest-slot"
; <slot-or-expr> --> <>; a "slot"
; | <expression>; a "non-slot expression"
(module cut mzscheme
(provide cut)
(define-for-syntax (fresh-name)
(car (generate-temporaries #'(cut))))
(define-for-syntax (substitute-<>-with-name expr)
(syntax-case expr (<>)
[<> (let ((name (fresh-name)))
(values (list name) name))]
[(a . d) (let-values ([(a-names a-expr) (substitute-<>-with-name #'a)]
[(d-names d-expr) (substitute-<>-with-name #'d)])
(values (append a-names d-names)
(quasisyntax/loc expr
(#,a-expr . #,d-expr))))]
[_ (values '() expr)]))
; generate-names/exprs :
; Given the arguments for the macro call to cut as a syntax-list,
; call build with two lists:
; 1) a list of names given to each <>-slot
; 2) [cut] a list of the macro arguments, except that all occurences
; of a <>-slots have been substituted with the chosen name.
(define-for-syntax (generate-names/exprs slot-or-exprs build)
(let loop ([slot-or-exprs (syntax->list slot-or-exprs)]
[slot-names '()]
[names-or-exprs '()])
(cond
[(null? slot-or-exprs) (build (reverse slot-names)
(reverse names-or-exprs))]
[else (let-values ([(names substituted-expr)
(substitute-<>-with-name (car slot-or-exprs))])
(loop (cdr slot-or-exprs)
(append (reverse names) slot-names)
(cons substituted-expr names-or-exprs)))])))
(require-for-syntax (lib "name.ss" "syntax"))
(define-for-syntax (make-inferred-cut-name stx)
(cond
[(identifier? stx) (string->symbol
(string-append
"specialized version of "
(symbol->string (syntax-e stx))
" originating from a cut"))]
[(syntax-property stx 'inferred-name) => (lambda (name)
(string->symbol
(string-append
"specialized version of "
(symbol->string name)
" originating from a cut")))]
[else #f]))
(define-for-syntax (set-inferred-name stx name)
(if name
(syntax-property stx 'inferred-name name)
stx))
(define-syntax (cut stx)
(syntax-case stx (<> <...>)
[(cut)
(raise-syntax-error #f "cut expects 1 or more slots or expressions, given none" stx)]
[(cut <>)
(raise-syntax-error #f "cut expects an expression at the first position, given a slot <>" stx)]
[(cut proc)
(set-inferred-name
#`(lambda () #,(syntax/loc stx (proc)))
(make-inferred-cut-name #'proc))]
[(cut <> slot-or-expr ...)
(raise-syntax-error #f "cut expects an expression at the first position, given a slot <>" stx)]
[(cut <...> slot-or-expr ...)
(raise-syntax-error #f "cut expects an expression at the first position, given <...>" stx)]
[(cut proc slot-or-expr ... <...>)
; Applying a wrong number of arguments to the the lamba generated by cut, will provoke an
; error caused by the application (proc ...). The quasisyntax/loc makes sure DrScheme
; shows the cut-expression as the source of the error in stead of showing an error in
; the code implementing the macro i.e. in this code.
; Note: Is it possible to propagate the error to the location of the wrong application
; in the user code?
(generate-names/exprs #'(slot-or-expr ...)
(lambda (slot-names names-or-exprs . ignored)
#`(lambda (#,@slot-names . xs)
#,(quasisyntax/loc stx
(apply proc #,@names-or-exprs xs)))))]
[(cut proc slot-or-expr ...)
(generate-names/exprs #'(slot-or-expr ...)
(lambda (slot-names names-or-exprs . ignored)
#`(lambda #,slot-names
#,(quasisyntax/loc stx
(proc #,@names-or-exprs)))))]))
)
;(require cut)
;> ((cut list '- (list <> (list '- <> <> '-)) (list <>) (list <> (list <> <>))) 2 3 4 5 6 7 8)
;(- (2 (- 3 4 -)) (5) (6 (7 8)))