On this page:
Overview
Arity dispatch
Representing overloaded definitions
Starter code
Submitting
9.2

Assignment 7: Arity-overloaded functions🔗

Due: Thursday, June 25, 11:59PM

Starter code: jig-plus.zip

The goal of this assignment is to implement arity-overloaded functions.

Overview🔗

For this assignment, use the starter code in jig-plus.zip, which is similar to the Jig language we studied in class.

You must extend the language with the features described here, plus you must bring forward the features from Assignment 6.

Arity dispatch🔗

Some languages such as Java, Haskell, and Racket make it possible to overload a single function name with multiple definitions where the dispatch between these different definitions is performed based on the number (or kind) of arguments given at a function call.

In Racket, this is accomplished with the case-lambda form for constructing multiple-arity functions.

Here is an example:

Examples

> (define f
    (case-lambda
      [(x) "got one!"]
      [(p q) "got two!"]))
> (f #t)

"got one!"

> (f #t #f)

"got two!"

> (f #t #f 0)

f: arity mismatch;

 the expected number of arguments does not match the given

number

  given: 3

This function can accept either one or two arguments. If given one argument, it evaluates the right-hand-side of the first clause with x bound to that argument. If given two arguments, it evaluates the right-hand-side of the second clause with p and q bound to the arguments. If given any other number of arguments, it signals an error.

A case-lambda form can have any number of clauses (including zero!) and the first clause for which the number of arguments is acceptable is taken when the function is called.

Note that case-lambda can be combined with rest arguments too. A clause that accepts any number of arguments is written by simply listing a parameter name (no parentheses). A clause that accepts some non-zero minimum number of parameters is written with a dotted parameter list.

For example:

Examples

> (define f
    (case-lambda
      [(x y z . r) (length r)]
      [(x) "just one!"]))
> (f 1 2 3 4 5 6)

3

> (f #t)

"just one!"

> (f)

f: arity mismatch;

 the expected number of arguments does not match the given

number

  given: 0

> (f 1 2)

f: arity mismatch;

 the expected number of arguments does not match the given

number

  given: 2

This function takes three or more arguments or one argument. Any other number of arguments (i.e. zero or two) results in an error.

Examples

> (define f
    (case-lambda
      [(x y z) "three!"]
      [xs (length xs)]))
> (f)

0

> (f 1 2)

2

> (f 1 2 3)

"three!"

> (f 1 2 3 4 5 6)

6

This function takes any number of arguments, but when given three, it produces "three!"; in all other cases it produces the number of arguments.

Representing overloaded definitions🔗

In this assignment, Iniquity+ adds a third kind of function representation:

; type Defn = (Defn Id Fun)
(struct Defn (f fun) #:prefab)
 
; type Fun = (FunPlain [Listof Id] Expr)
;          | (FunRest [Listof Id] Id Expr)
;          | (FunCase [Listof FunCaseClause])
; type FunCaseClause = (FunPlain [Listof Id] Expr)
;                    | (FunRest [Listof Id] Id Expr)
(struct FunPlain (xs e)   #:prefab)
(struct FunRest  (xs x e) #:prefab)
(struct FunCase  (cs)     #:prefab)

The parser already works for these new forms of function definitions. Here is an example of how overloaded function definitions are parsed:

Examples

> (parse-define
    '(define f
       (case-lambda
         [(x y) 2]
         [(z) 1]
         [(a b c . d) "3+"]
         [q "other"])))

'#s(Defn

    f

    #s(FunCase

       (#s(FunPlain (x y) #s(Lit 2))

        #s(FunPlain (z) #s(Lit 1))

        #s(FunRest (a b c) d #s(Lit "3+"))

        #s(FunRest () q #s(Lit "other")))))

Starter code🔗

The compiler code given to you supports plain function definitions. The interpreter code given to you works on the full Jig+ language, so you do not need to update interp.rkt and can use the interpreter to guide your implementation of the compiler.

Examples

> (interp
    (parse '(define f
              (case-lambda
                [(x y) 2]
                [(z) 1]
                [(a b c . d) "3+"]
                [q "other"]))
           '(cons (f 7)
              (cons (f 3 4)
                (cons (f)
                  (cons (f 7 8 9 10 11)
                        '()))))))

'(1 2 "other" "3+")

Thus, you should only need to modify compile.rkt.

A small number of test cases are given as usual.

Submitting🔗

To submit, use make from within the jig-plus directory to create a zip file containing your work and submit it to Gradescope.