Index: S-expressions, Variations on natural numbers
Many kinds of software needs to be able to represent a program as a piece of data. For example, to DrScheme, your programs are just pieces of data which it needs to understand how to evaluate. Such software needs a data definition of the programming language that is to be represented. Will will represent a subset of Scheme code as data, using the following definitions.
A S-expression is one of
The third case of S-expressions allows us to represent the clauses of a conditional. It also allows us to represent more general Scheme expressions that you'll see later in the course.
Let's make some example S-expressions:
S-expression | represented Scheme code |
---|---|
(list '+ 3 2)( | (+ 3 2) |
(list 'cons 19 'empty) | (cons 19 empty) |
(list 'cond (list #t 'x)) | (cond (#t x)) |
3 fred (symbol? 'hello)(Note that we could have defined a type to represent any Scheme expression, but the given definition is simpler to use.)
To do: Develop the function atom? : any -> boolean.
To do: Develop the template for functions of type
f : S-expression -> XFollow the data definition! You'll want to use atom?.
To do: Using this template, write the following functions. Where applicable, finish the examples.
;; subst : atom atom S-expression -> S-expression ;; returns an S-expression like s, except that new has been ;; substituted for each occurrence of old (define (subst new old s) ...) #| Example: (subst 'b 'a (cons (list 'a) (cons (list 'b 'c) (list 'a)))) = (cons (list 'b) (cons (list 'b 'c) (list 'b))) |#
This function is useful for implementing one of the rules for evaluating Scheme. When evaluating a Scheme function call, our rules say to replace the function call with the function body, except that we substitute the given argument(s) for the function's parameter(s). Here, new, old, and s would be the representations of the argument, parameter, and function body, respectively.
;; expand-or : S-expression -> S-expression ;; (define (expand-or s) ...) #| Example: (expand-and (list 'or 'foo 'bar)) = ... |#
This converts the representation of
(or foo bar)to the representation of the equivalent Scheme expression
(cond (foo #t) (else bar))
;; first-atom : S-expression -> (atom or empty)) ;; returns the first (leftmost) atom in s (define (first-atom s) ...) #| Example: (first-atom (cons (list 'a) (list 'b))) = 'a (first-atom empty) = empty |#
We have defined that a NatNum is either
If we wanted to start counting from some other number, say, 1 or 15 or -77, we could change our definition slightly. E.g., a NatNum[>=10] is either
To do: Make some example data for this type and write the appropriate template.
If we wanted to count downwards instead, we could again change our definition. E.g., a NatNum[<=10] is either
To do: Make some example data for this type and write the appropriate template.
Rather than forcing yourself to use some standard well-known data definition, it is often important to use your own variant which matches your needs more precisely. But, when you do so, it is extra important to be clear that you are not using the standard definition, so the reader is not confused.