From: "Julian Graham" <joolean@gmail.com>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guile-devel@gnu.org
Subject: Re: pass at srfi-89 implementation
Date: Thu, 21 Aug 2008 23:56:26 -0400 [thread overview]
Message-ID: <2bc5f8210808212056w3887ab74u40ecf7905eb60148@mail.gmail.com> (raw)
In-Reply-To: <2bc5f8210808161419x25fefebcp922d5def09958610@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 911 bytes --]
Alright, I give up. I'm still not exactly sure why my implementation
is as slow as it is; I have a hunch that I'm taking too long
processing the list of actual parameters, but I haven't been able to
glean many specifics from statprof. Marc also employs some nifty but
un-Scheme-y (to my mind, at least) tricks that give his version an
edge, like emitting code that destructively modifies the argument list
as part of determining where to insert default values.
At any rate, find my version attached. I think it's probably a dead
end in terms of going forward, but maybe it's salvageable by a more
experienced Schemer? ...Or maybe a more experienced Schemer could make
another attempt at doing an implementation from scratch? I don't know
what the right course is -- I think it would probably be easy to do
something performant in C, but I also grok why that's not the
preferred solution.
Regards,
Julian
[-- Attachment #2: srfi-89.scm --]
[-- Type: application/octet-stream, Size: 6945 bytes --]
(define-module (srfi srfi-89)
#:use-module (ice-9 receive)
#:use-module (srfi srfi-1)
#:use-module (srfi srfi-88)
#:export (
define*
lambda*))
(cond-expand-provide (current-module) '(srfi-89))
(define-macro (define* pattern . body)
(if (pair? pattern)
`(define ,(car pattern) (lambda* ,(cdr pattern) ,@body))
`(define ,pattern ,@body)))
(define variable? symbol?)
(define required? variable?)
(define (optional? x)
(and (proper-list? x) (= (length x) 2) (variable? (car x))))
(define (positional? x) (or (required? x) (optional? x)))
(define (named? x)
(and (proper-list? x)
(= (length x) 3)
(keyword? (car x))
(variable? (cadr x))))
(define-macro (lambda* formals . body)
;; Because Guile's SRFI-1 doesn't work on dotted lists
(define (length-permissive lst)
(if (null? lst)
0
(let ((clst (cdr lst)))
(if (pair? clst) (+ (length-permissive clst) 1) 2))))
(define (span-permissive pred lst)
(define (span-permissive-inner head tail)
(if (or (null? tail) (not (pair? tail)))
(values head tail)
(let ((ctail (car tail)))
(if (pred ctail)
(span-permissive-inner (append head (list ctail)) (cdr tail))
(values head tail)))))
(span-permissive-inner '() lst))
(define (emit required optional named rest named-first?)
(define (emit-positional reqv optv loptv nmdv rstv)
(define (emit-positional-tail)
(if (or named-first? (null? named))
(emit-rest rstv)
(emit-named reqv optv loptv nmdv rstv)))
(append
(fold (lambda (x c) (append c `((,x (vector-ref ,reqv ,(length c))))))
'()
required)
(if (null? optional)
(emit-positional-tail)
(let ((len (gensym))
(p (gensym)))
(append
(fold (lambda (x c)
(append c `((,x (if (> ,loptv ,(length c))
(vector-ref ,optv ,(length c))
,(list-ref (map cadr optional)
(length c)))))))
'()
(map car optional))
(emit-positional-tail))))))
(define (emit-named reqv optv loptv nmdv rstv)
(define (emit-named-tail)
(if named-first?
(emit-positional reqv optv loptv nmdv rstv)
(emit-rest rstv)))
(if (null? named)
(emit-named-tail)
(let ((handle-var (gensym)))
(append
(fold (lambda (x c)
(append c
`((,(cadr x)
(let ((,handle-var (hashq-get-handle
,nmdv ,(car x))))
(if ,handle-var
(cdr ,handle-var)
,(caddr x)))))))
'()
named)
(emit-named-tail)))))
(define (emit-rest rstv) (if rest `((,rest ,rstv)) '()))
(let* ((srfi-89:bound-required-var (gensym))
(srfi-89:bound-optional-var (gensym))
(srfi-89:bound-required-counter (gensym))
(srfi-89:bound-optional-counter (gensym))
(srfi-89:bound-named-var (gensym))
(srfi-89:bound-rest-var (gensym))
(srfi-89:process-args (gensym))
(srfi-89:num-required (length required))
(srfi-89:num-optional (length optional)))
`(lambda srfi-89:args
(let ,srfi-89:process-args
((,srfi-89:bound-required-var
,(if (null? required) #f `(make-vector ,srfi-89:num-required)))
(,srfi-89:bound-optional-var
,(if (null? required) #f `(make-vector ,srfi-89:num-required)))
(,srfi-89:bound-required-counter 0)
(,srfi-89:bound-optional-counter 0)
(,srfi-89:bound-named-var
,(if (null? named) #f `(make-hash-table)))
(,srfi-89:bound-rest-var '())
(lst srfi-89:args))
(if (null? lst)
(begin
(let* ,(if named-first?
(emit-named srfi-89:bound-required-var
srfi-89:bound-optional-var
srfi-89:bound-optional-counter
srfi-89:bound-named-var
srfi-89:bound-rest-var)
(emit-positional srfi-89:bound-required-var
srfi-89:bound-optional-var
srfi-89:bound-optional-counter
srfi-89:bound-named-var
srfi-89:bound-rest-var))
,@body))
(let ((cl (car lst)))
(cond ,(if (not (null? named))
`((keyword? cl)
(if (not (memq cl (quote ,(map car named))))
(error "unknown parameter keyword" cl))
(if (hashq-get-handle ,srfi-89:bound-named-var
cl)
(error "duplicate parameter" cl))
(hashq-set! ,srfi-89:bound-named-var
cl (cadr lst))
(,srfi-89:process-args
,srfi-89:bound-required-var
,srfi-89:bound-optional-var
,srfi-89:bound-required-counter
,srfi-89:bound-optional-counter
,srfi-89:bound-named-var
,srfi-89:bound-rest-var
(cddr lst)))
`(#f))
((< ,srfi-89:bound-required-counter
,srfi-89:num-required)
(vector-set! ,srfi-89:bound-required-var
,srfi-89:bound-required-counter
cl)
(,srfi-89:process-args
,srfi-89:bound-required-var
,srfi-89:bound-optional-var
(+ ,srfi-89:bound-required-counter 1)
,srfi-89:bound-optional-counter
,srfi-89:bound-named-var
,srfi-89:bound-rest-var
(cdr lst)))
((< ,srfi-89:bound-optional-counter
,srfi-89:num-optional)
(vector-set! ,srfi-89:bound-optional-var
,srfi-89:bound-optional-counter
cl)
(,srfi-89:process-args
,srfi-89:bound-required-var
,srfi-89:bound-optional-var
,srfi-89:bound-required-counter
(+ ,srfi-89:bound-optional-counter 1)
,srfi-89:bound-named-var
,srfi-89:bound-rest-var
(cdr lst)))
((quote ,rest) (,srfi-89:process-args
,srfi-89:bound-required-var
,srfi-89:bound-optional-var
,srfi-89:bound-required-counter
,srfi-89:bound-optional-counter
,srfi-89:bound-named-var
lst
'()))
(else (error "too many actual parameters")))))))))
(define (parse-1 positional named rest named-first?)
(receive (required optional)
(span-permissive required? positional)
(emit required optional named rest named-first?)))
(cond ((null? formals) `(lambda () ,@body))
((variable? formals) `(lambda ,formals ,@body))
((positional? (car formals))
(receive (positional named)
(span-permissive positional? formals)
(cond ((and (not (symbol? named)) (dotted-list? named))
(receive (named rest)
(split-at named
(- (length-permissive named) 1))
(parse-1 positional named rest #f)))
((list? named) (parse-1 positional named #f #f))
(else (parse-1 positional '() named #f)))))
((named? (car formals))
(receive (named positional)
(span-permissive named? formals)
(cond ((and (not (symbol? positional))
(dotted-list? positional))
(receive (positional rest)
(split-at positional
(- (length-permissive positional)
1))
(parse-1 positional named rest #t)))
((list? positional) (parse-1 positional named #f #t))
(else (parse-1 '() named positional #t)))))
(else (error "Error in formal parameter list"))))
prev parent reply other threads:[~2008-08-22 3:56 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-05-03 3:37 pass at srfi-89 implementation Julian Graham
2008-05-05 21:43 ` Ludovic Courtès
2008-05-19 20:15 ` Ludovic Courtès
2008-05-19 20:28 ` Julian Graham
2008-05-20 9:04 ` Ludovic Courtès
2008-05-25 5:08 ` Julian Graham
2008-05-27 7:43 ` Ludovic Courtès
2008-07-28 4:19 ` Julian Graham
2008-08-11 11:48 ` Ludovic Courtès
2008-08-16 21:19 ` Julian Graham
2008-08-18 18:41 ` Andy Wingo
2008-08-20 7:32 ` Ludovic Courtès
2008-08-20 20:14 ` Andy Wingo
2008-08-22 4:12 ` Julian Graham
2008-08-22 3:56 ` Julian Graham [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2bc5f8210808212056w3887ab74u40ecf7905eb60148@mail.gmail.com \
--to=joolean@gmail.com \
--cc=guile-devel@gnu.org \
--cc=ludo@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).