Wrote tests for the for: macros.

This commit is contained in:
Vincent St-Amour 2010-05-28 13:22:48 -04:00
parent 49caa00890
commit c92ae73859
3 changed files with 207 additions and 0 deletions

View File

@ -0,0 +1,115 @@
#lang typed/scheme
(: check (All (a) ((a a -> Boolean) a a -> Boolean)))
;; Simple check function as RackUnit doesn't work in Typed Scheme (yet)
(define (check f a b)
(if (f a b)
#t
(error (format "Check (~a ~a ~a) failed" f a b))))
(check string=?
(with-output-to-string
(lambda ()
(for: : Void ([i : Integer (in-range 10)])
(display i))))
"0123456789")
(check string=?
(with-output-to-string
(lambda ()
(for: : Void
((i : Exact-Positive-Integer '(1 2 3))
(j : Char "abc")
#:when (odd? i)
(k : True #(#t #t))
#:when k)
(display (list i j k)))))
"(1 a #t)(1 a #t)(3 c #t)(3 c #t)")
(check equal?
(for/list: : (Listof Integer) ([i : Integer (in-range 10)]) i)
'(0 1 2 3 4 5 6 7 8 9))
(check equal?
(for/list: : (Listof Integer)
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30))
#:when (odd? i))
(+ i j 10))
'(21 43))
(check equal?
(for/or: : Boolean
((i : Exact-Positive-Integer '(1 2 3)))
(>= i 3))
#t)
(check equal?
(for/or: : Boolean
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(2 1 3)))
(>= i j))
#t)
(check equal?
(let-values: ([([x : (Listof Integer)] [y : (Listof Integer)])
(for/lists: : (values (Listof Integer) (Listof Integer))
((x : (Listof Integer))
(y : (Listof Integer)))
((i : Exact-Positive-Integer '(1 2 3))
#:when #t
(j : Exact-Positive-Integer '(10 20 30))
#:when (> j 12))
(values i j))])
(append x y))
'(1 1 2 2 3 3 20 30 20 30 20 30))
(check =
(for/fold: : Integer
((acc : Integer 0))
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(+ acc i j))
66)
(check =
(for/fold: : Integer
((acc : Integer 0))
((i : Exact-Positive-Integer '(1 2 3))
#:when (even? i)
(j : Exact-Positive-Integer '(10 20 30))
#:when #t
(k : Exact-Positive-Integer '(100 200 300)))
(+ acc i j k))
1998)
(check string=?
(with-output-to-string
(lambda ()
(for*: : Void
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(display (list i j)))))
"(1 10)(1 20)(1 30)(2 10)(2 20)(2 30)(3 10)(3 20)(3 30)")
(check equal?
(let-values: ([([x : (Listof Integer)] [y : (Listof Integer)])
(for*/lists: : (values (Listof Integer) (Listof Integer))
((x : (Listof Integer))
(y : (Listof Integer)))
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30))
#:when (> j 12))
(values i j))])
(append x y))
'(1 1 2 2 3 3 20 30 20 30 20 30))
(check =
(for*/fold: : Integer
((acc : Integer 0))
((i : Exact-Positive-Integer '(1 2 3))
#:when (even? i)
(j : Exact-Positive-Integer '(10 20 30))
(k : Exact-Positive-Integer '(100 200 300)))
(+ acc i j k))
1998)

View File

@ -0,0 +1,55 @@
#lang typed/scheme
;; Inference fails when #:when clauses are used, except when there's
;; only one, and it's the last clause.
;; for:, for*: are unaffected, since they currently expand their
;; #:when clauses manually, unlike for/list: and co, who punt it to
;; non-annotated versions of the macros, to avoid breaking semantics.
;; for/fold:, for*/fold:, for/lists: and for*/lists: are not affected
;; either. The inferencer can handle their expansion, apparently no
;; matter how many #:when clauses we throw at them.
;; Of course, for*/list: and co won't work, since they are equivalent
;; to for/list: and co with #:when clauses.
(for/list: : (Listof Integer)
((i : Exact-Positive-Integer '(1 2 3))
#:when (odd? i)
(j : Exact-Positive-Integer '(10 20 30)))
(+ i j 10))
(for/list: : (Listof Integer)
(#:when #t
(i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(+ i j 10))
(for*/list: : (Listof (Listof Integer))
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(list i j))
;; The right type for the return value would be (values (Listof Integer) (Listof Integer)).
;; The problem here is with the error message. Somehow, source location information is lost and the whole module is blamed.
(for/lists: : (Listof Integer)
((x : (Listof Integer))
(y : (Listof Integer)))
((i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(values i j))
;; This is a legitimate use of multi-valued seq-exprs, but it causes the typechecker to throw an internal error.
(for/list: : (Listof Integer)
((([i : Exact-Positive-Integer]
[j : Exact-Positive-Integer])
(list (values 1 10) (values 2 20) (values 2 30)))
#:when (odd? i))
(+ i j 10))
;; Types can't be inferred for the expansion of for/first: at all.
(for/first: : Integer
((i : Exact-Positive-Integer '(1 2 3)))
i)
;; Same for for/last:
(for/last: : (Option Integer)
((i : Exact-Positive-Integer '(1 2 3)))
i)

View File

@ -0,0 +1,37 @@
#lang typed/scheme
;; I would have to be annotated with its most precise type (Exact-Positive-Integer) for this to work
(for: : Void ((i : Integer '(1 2 3)))
(display i))
;; same here, would need type (U (List 'a 't) (List 'c 'g))
(for: : Void
([from-to : (List Symbol Symbol)
'([a t]
[c g])])
#t)
;; wants (U False True), which should be the same as Boolean, but apparently isn't
(for: : Void
((k : Boolean #(#t #f))
#:when k)
(display k))
;; unlike the usual cases with #:when clauses (see for-inference.rkt), inference does something, but does it wrong
(for/list: : (Listof Integer)
(#:when #t
(i : Exact-Positive-Integer '(1 2 3))
(j : Exact-Positive-Integer '(10 20 30)))
(+ i j 10))
;; that same bug makes for/hash:, for/hasheq: and for/hasheqv: unusable
;; this infers Nothing for the type of the elements of the HashTable
;; since they don't work, these functions are not currently documented
(for/hash: : (HashTable Integer Char)
((i : Exact-Positive-Integer '(1 2 3))
(j : Char "abc"))
(values i j))
;; same thing for for/and:
(for/and: : Boolean
((i : Exact-Positive-Integer '(1 2 3)))
(< i 3))