AbigailB
AbigailB

Reputation: 339

Scheme Variable Arity on Higher-Order Function

I am new to Scheme and this is homework, so I am asking for hints rather than whole solutions. I am writing a procedure called type-checked that takes as arguments a procedure and zero or more type predicates. The value of the procedure is a variable-arity procedure: If its arguments match the corresponding types given to type-checked, then it returns the value of the procedure called on the arguments. Otherwise, it reports an error.

I have this procedure working for something like this:

((type-checked sqrt number?) 100)

But not for this:

((type-checked + number?) 1 2 3 4 5)

That is, I can run the procedure correctly with one argument, but not a variable number of arguments. Here is the pertinent code:

(define (type-checked procedure types)
  (lambda args
    (if (types-match? (list types) (list args))
        (procedure args)
        (error "type mismatch"))))

If I enclose args with parentheses, I can run it on one argument. Otherwise, I always get the type mismatch error.

Here is the recursive procedure that type-check calls. It checks to see if the types given match the arguments. I know it is not optimized, but for now my goal is working code. types-match? takes in two lists, type predicates and values, and checks to see if they all match. I have attempted to comment it in a way that makes sense. The code below seems to work on its own.

(define types-match?
  (lambda (types values)
    (if (= 1 (length types))                     ;if there is only one type left
        (if (null? values)                       ;if values is empty, finished
            #t
            (if ((car types) (car values))       ;else, check types with the rest of the list
                (types-match? types (cdr values))
                #f))
        (if (null? values) 
            #t 
            (if ((car types) (car values))       ;if there is more than one type in types, call
                (types-match? (cdr types) (cdr values)) ;compare with the first type in the list, then call on the rest of both types and values
                #f)))))

I am trying to figure out how to accept the variable number of arguments when calling the procedure. Any help is greatly appreciated, and thank you in advance!

Upvotes: 1

Views: 337

Answers (1)

Sylwester
Sylwester

Reputation: 48745

types needed to be a rest argument just like args, since both arguments are always lists of values you don't need to wrap them in lists and you need to use apply to use a list as multiple arguments to a procedure:

(define (type-checked procedure . types) ; types is a rest argument
  (lambda args                           ; args is a rest argument
    (if (types-match? types args)        ; both are lists
        (apply procedure args)           ; (apply + '(1 2)) == (+ 1 2)
        (error "type mismatch"))))

I spot that when you do the last iteration of a multiple type argument list it will assume all the last arguments are the last type you supplied. eg. the following will actually work:

((types-match? map procedure? list?) + '(1 2 3) '(1 2 3)) ; ==> (2 4 6)

Upvotes: 2

Related Questions