syndicate-2017/racket/typed/for-loops.rkt

220 lines
8.2 KiB
Racket
Raw Normal View History

2019-04-30 21:42:03 +00:00
#lang turnstile
(provide for/fold
2019-05-21 20:56:53 +00:00
for
for/list
for/set
2019-05-21 20:56:53 +00:00
for/sum
for/first)
2019-04-30 21:42:03 +00:00
(require "core-types.rkt")
(require "sequence.rkt")
(require (only-in "list.rkt" List ~List))
(require (only-in "set.rkt" Set ~Set))
(require (only-in "hash.rkt" Hash ~Hash))
(require (only-in "prim.rkt" Bool + #%datum))
2019-05-21 20:56:53 +00:00
(require (only-in "core-expressions.rkt" let unit))
(require "maybe.rkt")
(require (postfix-in - (only-in racket/set
for/set
in-set)))
2019-04-30 21:42:03 +00:00
(begin-for-syntax
(define-splicing-syntax-class iter-clause
#:attributes (parend)
#:datum-literals (:)
(pattern [x:id seq:expr]
#:attr parend #'[x seq])
(pattern [x:id : τ:type seq:expr]
#:attr parend #'[x : τ seq])
(pattern [(k:id v:id) hash-seq:expr]
#:attr parend #'[(k v) hash-seq])
(pattern (~seq #:when pred:expr)
#:attr parend #'(#:when pred))
(pattern (~seq #:unless pred:expr)
#:attr parend #'(#:unless pred))
(pattern (~seq #:break pred:expr)
#:attr parend #'(#:break pred))))
;; a Binding is a (SyntaxList Id Id Type), i.e. #'(x x- τ-x)
2019-04-30 21:42:03 +00:00
(begin-for-syntax
(struct loop-clause (exp bindings) #:transparent)
(struct directive (kw exp) #:transparent))
;; (SyntaxListOf LoopClause) -> (Syntax LoopClause- (Binding ...))
2019-04-30 21:42:03 +00:00
(define-for-syntax (analyze-for-clauses clauses)
(define-values (br binds)
(for/fold ([body-rev '()]
[bindings '()])
([clause (in-syntax clauses)])
(match (analyze-for-clause clause bindings)
2019-04-30 21:42:03 +00:00
[(loop-clause exp bs)
(values (cons exp body-rev)
(append bindings bs))]
[(directive kw exp)
(values (list* exp kw body-rev)
bindings)])))
#`(#,(reverse br)
#,binds))
;; iter-clause (Listof Binding) -> (U iter-clause directive)
(define-for-syntax (analyze-for-clause clause ctx)
(define/with-syntax ([y y- τ-y] ...) ctx)
2019-04-30 21:42:03 +00:00
(syntax-parse clause
#:datum-literals (:)
[[x:id seq:expr]
#:and (~typecheck
[[y y-- : τ-y] ... seq seq- ( : τ-seq)])
2019-04-30 21:42:03 +00:00
#:fail-unless (pure? #'seq-) "pure"
#:with x- (generate-temporary #'x)
2019-04-30 21:42:03 +00:00
#:do [(define-values (seq-- τ-elems) (make-sequence #'seq- #'τ-seq))]
(loop-clause (substs #'(y- ...) #'(y-- ...)
#`[x- #,seq--]
free-identifier=?)
(list #`(x x- #,τ-elems)))]
2019-04-30 21:42:03 +00:00
[[x:id : τ:type seq:expr]
#:with seq+ (add-expected-type #'seq #'τ.norm)
#:do [(match-define (list seq- (list (list x- τ-elems)))
(analyze-for-clause (syntax/loc clause [x seq+])))]
2019-04-30 21:42:03 +00:00
#:fail-unless (<: τ-elems #'τ.norm) "unexpected type"
(loop-clause #`[#,x- #,seq-]
(list #`(x #,x- τ.norm)))]
2019-04-30 21:42:03 +00:00
[[(k:id v:id) hash-seq:expr]
#:and (~typecheck
[[y y-- : τ-y] ... hash-seq hash-seq- ( : (~Hash K V))])
2019-04-30 21:42:03 +00:00
#:fail-unless (pure? #'hash-seq-) "pure"
#:with (k- v-) (generate-temporaries #'(k v))
(loop-clause (substs #'(y- ...) #'(y-- ...)
#`[(k- v-) (in-hash- hash-seq-)]
free-identifier=?)
(list #'(k k- K) #'(v v- V)))]
2019-04-30 21:42:03 +00:00
[(dir:keyword pred)
#:and (~typecheck
[[y y-- : τ-y] ... pred pred- ( : Bool)])
2019-04-30 21:42:03 +00:00
#:fail-unless (pure? #'pred-) "pure"
(directive #'dir (substs #'(y- ...) #'(y-- ...)
#'pred-
free-identifier=?))]))
2019-04-30 21:42:03 +00:00
;; Expression Type -> (Values Expression Type)
;; Determine what kind of sequence we're dealing with;
;; if it's not already in Sequence form, wrap the expression in the appropriate in-* form
;; also figure out what the type of elements are to associate with the loop variable
;; hashes handled separately
(define-for-syntax (make-sequence e τ)
(syntax-parse τ
[(~Sequence t)
(values e #'t)]
[(~List t)
(values #`(in-list- #,e) #'t)]
[(~Set t)
(values #`(in-set- #,e) #'t)]
[_
(type-error #:src e
#:msg "not an iterable type: ~a" τ)]))
2019-04-30 21:42:03 +00:00
(define-typed-syntax for/fold
[(for/fold ([acc:id (~optional (~datum :)) τ-acc init])
(clause:iter-clause
...)
e-body ...+)
[ init init- ( : τ-acc)]
#:fail-unless (pure? #'init-) "expression must be pure"
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ...
2019-04-30 21:42:03 +00:00
[acc acc- : τ-acc] (begin e-body ...) e-body-
( : τ-acc)
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
#:with e-body-- (substs #'(x- ...) #'(x-- ...) #'e-body- free-identifier=?)
2019-04-30 21:42:03 +00:00
-------------------------------------------------------
[ (for/fold- ([acc- init-])
clauses-
e-body--)
2019-04-30 21:42:03 +00:00
( : τ-acc)
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))]]
[(for/fold ([acc:id init])
clauses
e-body ...+)
[ init _ ( : τ-acc)]
---------------------------------------------------
[ (for/fold ([acc τ-acc init])
clauses
e-body ...)]])
(define-typed-syntax (for/list (clause:iter-clause ...)
e-body ...+)
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ... (begin e-body ...) e-body-
( : τ-body)
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
#:with e-body-- (substs #'(x- ...) #'(x-- ...) #'e-body- free-identifier=?)
----------------------------------------------------------------------
[ (for/list- clauses-
e-body--) ( : (List τ-body))
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))])
(define-typed-syntax (for/set (clause:iter-clause ...)
e-body ...+)
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ... (begin e-body ...) e-body-
( : τ-body)
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
#:with e-body-- (substs #'(x- ...) #'(x-- ...) #'e-body- free-identifier=?)
----------------------------------------------------------------------
[ (for/set- clauses-
e-body--) ( : (Set τ-body))
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))])
(define-typed-syntax (for/sum (clause ...)
e-body ...+)
----------------------------------------------------------------------
[ (for/fold ([acc 0])
(clause ...)
(+ acc (let () e-body ...)))])
2019-05-21 20:56:53 +00:00
(define-typed-syntax (for (clause ...)
e-body ...+)
----------------------------------------------------------------------
[ (for/fold ([acc unit])
(clause ...)
e-body ...
acc)])
(define-typed-syntax (for/first (clause:iter-clause ...)
e-body ...+)
#:with (clauses- ([x x- τ] ...)) (analyze-for-clauses #'(clause.parend ...))
[[x x-- : τ] ... (begin e-body ...) e-body-
( : τ-body)
( ν-ep (~effs τ-ep ...))
( ν-s (~effs τ-s ...))
( ν-f (~effs τ-f ...))]
#:with e-body-- (substs #'(x- ...) #'(x-- ...) #'e-body- free-identifier=?)
[[res _ : τ-body] res res- ( : _)]
----------------------------------------------------------------------
[ (let- ()
(define- res-
(for/first- clauses-
e-body--))
(if- res-
(some res-)
none))
( : (Maybe τ-body))
( ν-ep (τ-ep ...))
( ν-s (τ-s ...))
( ν-f (τ-f ...))])