CS403: Programming Languages

Assignment 3

Version 1b

Printable Version

Preliminary information

This is your third Scam assignment. To run your code, use the following command:
    scam FILENAME
    scam -r FILENAME
where FILENAME is replaced by the name of the program you wish to run. The -r option will automatically run a no-argument function named main on startup.

All assignment submissions should supply a program named author.scm. This program should look like:
    (define (main)
        (println "AUTHOR: Rita Recursion rrita@crimson.ua.edu")
with the name and email replaced by your own name and email.

For each numbered task (unless otherwise directed), you are to provide a program named taskN.scm, with the N corresponding to the task number, starting at one (as in task1.scm, task2.scm, and so on).

You may not use assignment, unless otherwise directed. You may not use a looping function such as while or for, unless otherwise directed. Do not use the comment-out-the rest-of-the-file comment in your code. Make sure you submit text files, not binary files. On any line of output, there should be no leading whitespace and no trailing whitespace other than a newline (except when otherwise directed).

ANY ATTEMPT TO FOOL THE GRADING SCRIPT, NO MATTER HOW SMALL, WILL RESULT IN A GRADE OF ZERO WITH NO ABILITY TO RESUBMIT. This penalty can be applied retroactively at any time during or after the semester.


  1. Define a predicate named scoping that determines whether a symbol is bound, free, or undefined with respect to an object. The call:
        (scoping 'y ((define (zurp x) (define y (+ x 1)) this) 5))
    should return the symbol bound because y is a locally defined variable. The call:
        (scoping '* ((define (zarp x) this) 5))
    should return the symbol free because * is not locally defined in the function zarp.

    Finally, the call:
        (scoping 'cs403sucks ((define (zirp x) this) 5))
    should return the symbol undefined because who would define a variable like that?

    Use the function ppTable to help you decompose scopes/objects. Do not use catch in your solution.

        $ cat task1.args
        (println (scoping 'cs403sucks ((define (zirp x) this) 5)))
        $ scam -r task1.scm task1.args
  1. Define a function named replace that replaces all occurrences of a given symbol in a function definition with a given value. You can obtain the body of a function definition as follows:
        (define (square x) (* x x))
        (define body (get 'code square))
        (inspect body)
    You can get the formal parameters by substituting 'parameters for 'code in the get expression. The code inspection displays the list (begin (* x x)) whose car is the symbol begin and whose cadr is the list (* x x).

    You can update the body of the function as follows:
        (set 'code '(begin (+ x x)) square)
        (inspect (square 5))
    The inspection should display the value 10. Likewise, you can update the formal parameters.

    A call to replace might look like:
        (replace square (list '* + '+ *))
    This call would replace the times symbol with the adding built-in and the plus symbol with the multiplying built-in.

    You can use the replace function to speed up the execution of any function.

    Your replace function needs to work recursively. That is to say, it needs to replace the symbol in all local function definitions, including lambdas. You may find the predicate functions object? useful this feature as you should not descend into these kinds of objects. Neither should you process any quoted expression. You may assume the given function performs no assignments of any kind.

        $ cat task2.args
        (define (abs n) (if (< n 0) (- n) n))
        (replace abs (list '< < '- -))
        (inspect (get 'code abs))
        $ scam -r task2.scm task2.args
        (get (quote code) abs) is (begin (if (<builtin <(@)> n 0) (<builtin -(@)> n) n))
    You may use assignment for this task.
  1. Define a double-ended queue class called deque. Your class should support the following methods:
        ((dq'enqueueFront) value)
        ((dq'enqueueBack) value)
        ((dq'enqueueIndex) index value)
        ((dq'dequeueIndex) index)
    The enqueue methods should return the item enqueued while the dequeue methods should return the item dequeued. All methods should run in constant time except enqueueIndex and dequeueIndex. The enqueueIndex method runs in constant time when the index is a constant distance from the front and in linear time otherwise. Likewise, the dequeueIndex method runs in constant time when the index is a constant distance from the back and in linear time otherwise. The enqueueIndex function places the new value such that it occupies the given index, using zero-based counting. The dequeueIndex also uses zero-based counting and returns the item dequeued. The display function prints out the values in the dequeue, separated by commas with no added spaces.

        $ cat task3.args
        (define dq (deque))
        ((dq'enqueueFront) 3)
        ((dq'enqueueBack) 5)
        (inspect ((dq'dequeueFront)))
        (inspect ((dq'dequeueBack)))
        (inspect (dq'size))
        (print "-")
        (println "-")
        $ scam -r task3.scm task3.args
        ((dq (quote dequeueFront))) is 3
        ((dq (quote dequeueBack))) is 5
        (dq (quote size)) is 0
    You may use assignment for this task.
  1. NAND is considered a universal set as any logical expression can be built solely with NAND gates. Define the constructors inverter, and-gate, or-gate, nor-gate, xor-gate, and xnor-gate, built entirely from NAND gates. Your gates need to be minimal. Name your NAND gate constructor nand-gate. Follow the style of the book in implemting your gate. Assume a nand-gate delay of 6 time units and hard-wire this number into your nand-gate function. Use the logic gate system of the text to implement NAND and the gates built with NANDs. You can download the base system (priority queue and wires/probes):
        wget beastie.cs.ua.edu/proglan/queue.scm
        wget beastie.cs.ua.edu/proglan/gates.scm
    Use your gates to build a half-adder and a full-adder, as in the text.

    Place your nand-gate function by itself (with no other functions) in a file named nand.scm and include that file in your task file: You will also need to make the agenda in your task file:

        (include "queue.scm")
        (include "gates.scm")
        (include "nand.scm")
        (define the-agenda (make-agenda))
        (define (main) ...)
        $ cat task4.args
        (define input-1 (make-wire))
        (define input-2 (make-wire))
        (define sum (make-wire))
        (define carry (make-wire))
        (probe 'sum sum)
        (probe 'carry carry)
        (half-adder input-1 input-2 sum carry)
        (set-signal! input-1 1)
        (set-signal! input-2 1)
        $ scam -r task4.scm task4.args
        sum 0  New-value = 0
        carry 0  New-value = 0
        carry 6  New-value = 1
        sum 6  New-value = 1
        carry 12  New-value = 0
        sum 12  New-value = 0
        sum 18  New-value = 1
        sum 24  New-value = 0
        sum 30  New-value = 1
        carry 42  New-value = 1
        sum 60  New-value = 0
    The extra newline at the beginning is due to the way the text implements the probe function. You may use assignment for this task.
  1. Define a function named smush that takes a stream of the form ( a , b , c , d , . . . ) and the operator Φ and returns the stream ( ( 0 , a , a ) , ( 1 , b , a Φ b ) , ( 2 , c , a Φ b Φ c ) , ( 3 , d , a Φ b Φ c Φ d ) , . . . ), only flattened. You will also need to define a stream displaying function named sdisplay. See the example below for its behavior.

        $ cat task5.args
        (define ones (cons-stream 1 ones))
        (sdisplay 12 (smush ones +))
        $ scam -r task5.scm task5.args
    For every triplet, the first number, i, is the index of the second number in the original stream. The third number is the accumulation of the first zero through i elements. Use left associativity when combining.
  1. Define a series of functions for mathematically manipulating a quadratic equation represented as a stream. The first, quad, takes the three coefficients of the quadratic plus a step value. For example, (quad 1 3 -4 0.01) would produce the stream representing the equation f = x 2 + 3 x - 4. The step argument, s, gives the distance between evaluations of the quadratic, starting at zero. The stream produced would be equivalent to ( f ( 0 ) , f ( s ) , f ( 2 s ) , f ( 3 s ) , . . . ).

    The second function, integrate, produces a stream representing the integral of the given stream. You should use the trapezoid method to compute the area under the curve. The first element of the integrated stream would be zero; the second element would be computed from a trapezoid having f ( 0 ) as the left height and f ( s ) as the right height. The integrate function takes two arguments, the stream to integrate and the step size. The i t h element of the resulting stream should approximate:

    0 i * s f ( x ) x
    The third function, derivate, produces a stream representing the derivative of the given stream. It should reverse the integration process. The derivate function takes three arguments, the stream to differentiate, the step size, and a constant. If f(0) is given as the constant, then an integrated quadratic stream passed to derivate should produce the original quadratic stream.

    A fourth function, same-stream? will help you decide if a differentiated integral stream is the same as the original stream. Given two streams, s1 and s2, a count n, and a positive threshold t, returns true if all of the first nth elements (piecewise) differ by less than t and false otherwise.

        $ cat task6.args
        (define qs (quad 1 0 0 1))
        (define is (integrate qs 1))
        (define ds (derivate is 1 0))
        (sdisplay 5 qs) (println)
        (sdisplay 5 is) (println)
        (sdisplay 5 ds) (println)
        (inspect (same-stream? qs ds 10 .001))
        $ scam -r task6.scm task6.args
        (same-stream? qs ds 10 0.0010000000) is #t
  1. Consider this series:

    1 - x 2 2 ! + x 4 4 ! - x 6 6 ! + x 8 8 ! - . . .
    Define a function named mystery that returns the stream that holds the terms of the above series for a given x. Define a function named ps-mystery that produces the stream of partial sums of (mystery x). Define a function named acc-mystery that accelerates (ps-mystery x) using the Euler transform. Define a function named super-mystery that produces a super accelerated stream using a tableau of ever-accelerated partial sum streams. All of these function takes x as their sole arguments. Define a function named symbolic-mystery that prints the symbolic result (as a LaTeX math expression) of the series sum, when taken out to infinity. For example, if the answer is π, then (mystery x) is $\pi$ would be printed. If the answer is log π, then (mystery x) is $\log\pi$ would be printed. In this last example, note the lack of parentheses. If there is more than one reasonable way to represent the answer, prefer the one with the fewer number of characters in the LaTeX expression. Prefer symbolic renderings over numeric ones and integers over integers rendered as real numbers. Do not use parentheses except for grouping. If you are unsure which rendering is best, ask me privately. Note that the dollar signs in the output are mandatory. Do not share this answer in any way.

        $ cat task7.args
        (define x 0)
        (sdisplay 5 (mystery x)) (println)
        (sdisplay 5 (ps-mystery x)) (println)
        (sdisplay 5 (acc-mystery x)) (println)
        (sdisplay 5 (super-mystery x)) (println)
        $ scam -r task7.scm task7.args
        (mystery x) is $\log\pi$
    Of course, log π is not the answer. Or is it?
  1. Exercise 3.71 in the text. Define a function named ramanujan that produces a stream of Ramanujan numbers. The function takes no arguments.

        $ cat task8.args
        (sdisplay 1 (ramanujan)) (println)
        $ scam -r task8.scm task8.args

Handing in the tasks

For preliminary testing, send me all the files in your directory by running the command:
    submit proglan lusth test3
For your final submission, use the command:
    submit proglan lusth assign3

Change log