trivial/private/function.rkt
ben 04835b5339 [6.4] move package to toplevel
Because pkgs.racket-lang doesn't seem to accept paths like
  .../repo.git#branch?tag

So I'm trying to remove the ?tag
2016-04-09 09:39:33 -04:00

94 lines
2.7 KiB
Racket

#lang typed/racket/base
;; TODO
;; map passing, but cury failig; can't make a lambda like I'd like to
;; -----------------------------------------------------------------------------
;; Track procedure arity
;; Applications:
;; - vectorized ops
;; - (TODO) improve apply/map? ask Leif
;; - TODO get types, not arity
(provide
curry:
map:
;; --
(for-syntax
fun-define
fun-let)
)
;; -----------------------------------------------------------------------------
(require
(for-syntax
typed/racket/base
syntax/parse
racket/syntax
trivial/private/common
))
;; =============================================================================
(begin-for-syntax
(define TYPE-KEY 'type-label)
(define (formal->type x)
(or (syntax-property x TYPE-KEY)
(format-id x "Any"))) ;; Could just use TR's Any from here
(define (parse-procedure-arity stx)
(syntax-parse stx #:literals (: #%plain-lambda lambda)
[(#%plain-lambda (x*:id ...) e* ...)
(map formal->type (syntax-e #'(x* ...)))]
;; TODO polydots, keywords, optional args
;; TODO standard library functions
[_ #f]))
(define-values (arity-key fun? fun-define fun-let)
(make-value-property 'procedure:arity parse-procedure-arity))
(define-syntax-class/predicate procedure/arity fun?)
)
;; -----------------------------------------------------------------------------
(define-syntax (curry: stx)
(syntax-parse stx
[(_ p:procedure/arity)
#:with x* (for/list ([_t (in-list (syntax-e #'p.evidence))]) (gensym))
#:with p+ (for/fold ([e (quasisyntax/loc stx (p.expanded #,@#'x*))])
([x (in-list (reverse (syntax-e #'x*)))]
[t (in-list (syntax-e #'p.evidence))])
(quasisyntax/loc stx
(lambda ([#,x : #,t]) #,e)))
(syntax/loc stx p+)]
[_
(raise-user-error 'curry "Fail at: ~a" (syntax->datum stx))]))
;; TODO try the other direction, inferring type from arguments.
;; (may not be practical here, may need to be inside TR)
(define-syntax map: (make-alias #'map
(lambda (stx) (syntax-parse stx
[(_ p:procedure/arity e* ...)
;; --
#:when
(let ([num-expected (length (syntax-e #'p.evidence))]
[num-actual (length (syntax-e #'(e* ...)))])
(unless (= num-expected num-actual)
(apply raise-arity-error
'map:
num-expected
(map syntax->datum (syntax-e #'(e* ...))))))
;; --
#:with Listof-stx (format-id stx "Listof")
#:with (e+* ...)
(for/list ([t (in-list (syntax-e #'p.evidence))]
[e (in-list (syntax-e #'(e* ...)))])
(quasisyntax/loc stx (ann #,e (Listof-stx #,(format-id stx "~a" (syntax-e t))))))
(syntax/loc stx (map p.expanded e+* ...))]))))