Add syntax for defining pseudovariadic functions.

This commit is contained in:
Sergiu Ivanov 2022-03-20 20:42:29 +01:00
parent 8b838c0b22
commit 8fb5bab803
2 changed files with 76 additions and 0 deletions

View file

@ -15,6 +15,7 @@
(for-syntax syntax/parse)) (for-syntax syntax/parse))
(provide (provide
pseudovariadic-lambda pvλ pseudovariadic-define pvdefine
tabulate* tabulate*/strict tabulate tabulate/strict) tabulate* tabulate*/strict tabulate tabulate/strict)
(unsafe-provide (unsafe-provide
@ -24,6 +25,57 @@
(module+ test (module+ test
(require typed/rackunit)) (require typed/rackunit))
(begin-for-syntax
(require racket (for-syntax syntax/parse))
(define (make-pseudovariadic-core args bodies tag-stx)
(define nargs-stx (datum->syntax args (length (syntax->list args))))
#`(λ xs
(match xs
[(list #,@args) #,@bodies]
[_ (error #,tag-stx "invalid arity, expected ~a argument(s)" #,nargs-stx)])))
(define (make-pseudovariadic-lambda stx)
(syntax-parse stx
[(_ (args:id ...) bodies:expr ...)
(make-pseudovariadic-core #'(args ...)
#'(bodies ...)
(datum->syntax stx ''pseudovariadic-lambda))]))
(define (make-pseudovariadic-define stx)
(syntax-parse stx
[(_ (name:id args:id ...) bodies:expr ...)
#`(define name
#,(make-pseudovariadic-core
#'(args ...)
#'(bodies ...)
(datum->syntax #'name `(quote ,(syntax->datum #'name)))))])))
(define-syntax (pseudovariadic-lambda stx) (make-pseudovariadic-lambda stx))
(define-syntax (pvλ stx) (make-pseudovariadic-lambda stx))
(module+ test
(test-case "pseudovariadic-lambda")
(check-false ((pseudovariadic-lambda (x y) (and x y)) #t #f))
(check-false ((pvλ (x y) (and x y)) #t #f))
(check-exn exn:fail? (λ () ((pseudovariadic-lambda (x y) (and x y)) #t #f #f)))
(check-exn exn:fail? (λ () ((pvλ (x y) (and x y)) #t #f #f))))
(define-syntax (pseudovariadic-define stx) (make-pseudovariadic-define stx))
(define-syntax (pvdefine stx) (make-pseudovariadic-define stx))
(module+ test
(test-case "pseudovariadic-define")
(: f (-> Boolean * Boolean))
(pseudovariadic-define (f x y) (and x y))
(check-false (f #t #f))
(check-exn exn:fail? (λ () (f #t #f #f)))
(: g (-> Boolean * Boolean))
(pvdefine (g x y) (and x y))
(check-false (g #t #f))
(check-exn exn:fail? (λ () (g #t #f #f))))
(define-syntax (make-tabulate* stx) (define-syntax (make-tabulate* stx)
(syntax-parse stx (syntax-parse stx
[(_ name:id row-op) [(_ name:id row-op)
@ -81,6 +133,7 @@
(require 'typed) (require 'typed)
(provide (provide
pseudovariadic-lambda pvλ pseudovariadic-define pvdefine
tabulate* tabulate*/strict tabulate*/untyped tabulate tabulate/strict tabulate* tabulate*/strict tabulate*/untyped tabulate tabulate/strict
tabulate/untyped) tabulate/untyped)

View file

@ -48,6 +48,29 @@ when they receive a number of arguments different from a given constant value.
Such functions are called @italic{pseudovariadic functions} in Such functions are called @italic{pseudovariadic functions} in
this documentation. this documentation.
@deftogether[(@defform[(pseudovariadic-lambda (id ...+) body ...+)]
@defform[(pvλ (id ...+) body ...+)])]{
Define a pseudovariadic anonymous function.
@examples[#:eval functions-evaluator
(: f (-> Boolean * Boolean))
(define f (pseudovariadic-lambda (x y) (and x y)))
(f #t #f)
(eval:error (f #t #f #t))
]}
@deftogether[(@defform[(pseudovariadic-define (name id ...+) body ...+)]
@defform[(pvdefine (id ...+) body ...+)])]{
Define a pseudovariadic function called @racket[name].
@examples[#:eval functions-evaluator
(: g (-> Boolean * Boolean))
(pseudovariadic-define (g x y) (and x y))
(g #t #f)
(eval:error (g #t #f #t))
]}
@section[#:tag "tabulating"]{Tabulating functions} @section[#:tag "tabulating"]{Tabulating functions}
@defproc[(tabulate [func (-> a ... b)] @defproc[(tabulate [func (-> a ... b)]