From 4f761ddb2f44f4cd4961984c8c2cb65fa39f71ae Mon Sep 17 00:00:00 2001 From: Stevie Strickland Date: Fri, 1 Jul 2011 11:59:14 -0400 Subject: [PATCH] Use fold-left instead of map for an example of a nonuniform vararg function. Fixes PR12014. --- .../scribblings/guide/varargs.scrbl | 65 +++++++++++-------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/collects/typed-scheme/scribblings/guide/varargs.scrbl b/collects/typed-scheme/scribblings/guide/varargs.scrbl index b01c190bfd..2903ad6cd6 100644 --- a/collects/typed-scheme/scribblings/guide/varargs.scrbl +++ b/collects/typed-scheme/scribblings/guide/varargs.scrbl @@ -1,6 +1,6 @@ #lang scribble/manual -@begin[(require "../utils.rkt" (for-label typed/racket/base))] +@begin[(require "../utils.rkt" (for-label typed/racket/base) (for-label (only-in rnrs/lists-6 fold-left)))] @title[#:tag "varargs"]{Variable-Arity Functions: Programming with Rest Arguments} @@ -43,63 +43,74 @@ of the rest parameter is used at the same type. @section{Non-Uniform Variable-Arity Functions} However, the rest argument may be used as a heterogeneous list. -Take this (simplified) definition of the Racket function @racket[map]: +Take this (simplified) definition of the R6RS function @racket[fold-left]: @racketmod[ racket -(define (map f as . bss) +(define (fold-left f i as . bss) (if (or (null? as) (ormap null? bss)) - null - (cons (apply f (car as) (map car bss)) - (apply map f (cdr as) (map cdr bss))))) + i + (apply fold-left + f + (apply f i (car as) (map car bss)) + (cdr as) + (map cdr bss)))) -(map add1 (list 1 2 3 4)) -(map cons (list 1 2 3) (list (list 4) (list 5) (list 6))) -(map + (list 1 2 3) (list 2 3 4) (list 3 4 5) (list 4 5 6))] +(fold-left + 0 (list 1 2 3 4) (list 5 6 7 8)) +(fold-left + 0 (list 1 2 3) (list 2 3 4) (list 3 4 5) (list 4 5 6)) +(fold-left (λ (i v n s) (string-append i (vector-ref v n) s)) + "" + (list (vector "A cat" "A dog" "A mouse") + (vector "tuna" "steak" "cheese")) + (list 0 2) + (list " does not eat " "."))] Here the different lists that make up the rest argument @racket[bss] can be of different types, but the type of each list in @racket[bss] corresponds to the type of the corresponding argument of @racket[f]. We also know that, in order to avoid arity errors, the length of -@racket[bss] must be one less than the arity of @racket[f] (as -@racket[as] corresponds to the first argument of @racket[f]). +@racket[bss] must be two less than the arity of @racket[f]. +The first argument to @racket[f] is the accumulator, +and @racket[as] corresponds to the second argument of @racket[f]. -The example uses of @racket[map] evaluate to @racketresult[(list 2 3 4 5)], -@racketresult[(list (list 1 4) (list 2 5) (list 3 6))], and -@racketresult[(list 10 14 18)]. +The example uses of @racket[fold-left] evaluate to @racketresult[36], +@racketresult[42], and @racketresult["A cat does not eat cheese."]. -In Typed Racket, we can define @racket[map] as follows: +In Typed Racket, we can define @racket[fold-left] as follows: @racketmod[ typed/racket -(: map +(: fold-left (All (C A B ...) - ((A B ... B -> C) (Listof A) (Listof B) ... B + ((C A B ... B -> C) C (Listof A) (Listof B) ... B -> - (Listof C)))) -(define (map f as . bss) + C))) +(define (fold-left f i as . bss) (if (or (null? as) (ormap null? bss)) - null - (cons (apply f (car as) (map car bss)) - (apply map f (cdr as) (map cdr bss)))))] + i + (apply fold-left + f + (apply f i (car as) (map car bss)) + (cdr as) + (map cdr bss))))] Note that the type variable @racket[B] is followed by an ellipsis. This denotes that B is a dotted type variable which corresponds to a list of types, much as a rest argument corresponds to a list of values. When the type -of @racket[map] is instantiated at a list of types, then +of @racket[fold-left] is instantiated at a list of types, then each type @racket[t] which is bound by @racket[B] (notated by the dotted pre-type @racket[t ... B]) is expanded to a number of copies of @racket[t] equal to the length of the sequence assigned to @racket[B]. Then @racket[B] in each copy is replaced with the corresponding type from the sequence. -So the type of @racket[(inst map Integer Boolean String Number)] +So the type of @racket[(inst fold-left Integer Boolean String Number)] is -@racket[((Boolean String Number -> Integer) - (Listof Boolean) (Listof String) (Listof Number) +@racket[((Integer Boolean String Number -> Integer) + Integer (Listof Boolean) (Listof String) (Listof Number) -> - (Listof Integer))]. + Integer)].