Skip to content

Commit 49337b2

Browse files
committed
WIP: Redefine for/first and for*/first.
1 parent fa598b6 commit 49337b2

File tree

1 file changed

+39
-6
lines changed
  • typed-racket-lib/typed-racket/base-env

1 file changed

+39
-6
lines changed

typed-racket-lib/typed-racket/base-env/prims.rkt

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -371,13 +371,10 @@ the typed racket language.
371371
stx
372372
(begin (define-syntax name (define-for-variant #'untyped-name)) ...))]))
373373

374-
;; for/first: and for/and:'s expansions
375-
;; can't currently be handled by the typechecker.
376374
(define-for-variants
377375
(for/list: for/list)
378376
(for/and: for/and)
379-
(for/or: for/or)
380-
(for/first: for/first))
377+
(for/or: for/or))
381378

382379
;; Unlike with the above, the inferencer can handle any number of #:when
383380
;; clauses with these 3.
@@ -461,8 +458,7 @@ the typed racket language.
461458
...))]))
462459
(define-for*-variants
463460
(for*/and: for*/and)
464-
(for*/or: for*/or)
465-
(for*/first: for*/first))
461+
(for*/or: for*/or))
466462

467463
;; Like for/lists:, for/fold: and for/foldr:, the inferencer can handle these correctly.
468464
(define-syntaxes (for*/lists:)
@@ -555,6 +551,43 @@ the typed racket language.
555551
(for/product: for/fold: for/product #f * 1 #%expression)
556552
(for*/product: for*/fold: for*/product #t * 1 #%expression))
557553

554+
(define-for-syntax (define-for/acc:-break-variant for*? for/folder: for/folder op break-op initial final)
555+
(lambda (stx)
556+
(syntax-parse stx #:literals (:)
557+
[(_ a1:optional-standalone-annotation*
558+
clause:for-clauses
559+
a2:optional-standalone-annotation*
560+
c ...) ; c is not always an expression, can be a break-clause
561+
(define a.ty (or (attribute a2.ty)
562+
(attribute a1.ty)))
563+
(cond
564+
[a.ty
565+
;; ty has to include exact 0, exact 1, null (sum/product/list respectively),
566+
;; the initial value of the accumulator
567+
;; (to be consistent with Racket semantics).
568+
;; We can't just change the initial value to be 0.0 if we expect a
569+
;; Float result. This is problematic in some cases e.g:
570+
;; (for/sum: : Float ([i : Float '(1.1)] #:when (zero? (random 1))) i)
571+
(quasisyntax/loc stx
572+
(#,final
573+
(#,for/folder: : #,a.ty ([acc : #,a.ty #,initial])
574+
(clause.expand ... ...)
575+
#:break (#,break-op acc #,initial)
576+
(let ([new (let () c ...)])
577+
(#,op acc new)))))]
578+
;; With no annotation, try our luck with the core form.
579+
;; Exact base cases cause problems, thus the additional
580+
;; annotation on the accumulator above.
581+
[for*? ((define-for*-variant for/folder) stx)]
582+
[else ((define-for-variant for/folder) stx)])])))
583+
584+
(define-syntax for/first:
585+
(define-for/acc:-break-variant
586+
#f 'for/fold: 'for/first 'begin (λ (x y) (not (equal? x y))) #f '#%expression))
587+
(define-syntax for*/first:
588+
(define-for/acc:-break-variant
589+
#t 'for*/fold: 'for*/first 'begin (λ (x y) (not (equal? x y))) #f '#%expression))
590+
558591
;; originally, we made the mistake of providing these by default in typed/racket/base
559592
;; so now we have this trickery here
560593
;; This trickery is only used for `typed/racket/base`; `typed/racket` just provides the

0 commit comments

Comments
 (0)