In this homework (and in all future homeworks) you should be working in the
βModuleβ language, and use the appropriate language using a #lang line. You should also click the βShow Detailsβ button in the language selection dialog, and check the βSyntactic test suite coverageβ option to see parts of your code that are not covered by tests: after you click βrunβ, parts of the code that were covered will be colored in green, parts that were not covered will be colored in red, and if you have complete coverage, then the colors will stay the same. Note that you can also set the default language that is inserted into new programs to #lang pl, to make things more convenient. There are some variants for the pl language for various purposes β in particular, #lang pl untyped will ignore all type declarations, and will essentially run your code in an untyped Racket.
The language for this homework is:
#lang pl 02
As in previous assignment, you need to use the special form for tests: test.
Β
Reminders (this is more or less the same as the administrative instructions for the previous assignment):
Comments: Submitted code for each question should include at least two lines of comments with your personal description of the solution, the function and its type. In addition, you should comment on the process of solving this question β what were the main difficulties, how you solved them, how much time did you invest in solving it, did you need to consult others. A solution without proper comments may be graded 0. In general, comments should appear above the definition of each procedure (to keep the code readable).
Tests: For each question, you should have enough test cases for complete coverage (DrRacket indicates covered expressions with colors for covered and uncovered source code, unless your code is completely covered). See below on the way to create tests. Note that your tests should not only cover the code, but also all end-cases and possible pitfalls.
Β
Important: Your tests should cover your whole code; otherwise the server will heavily penalize your submission. You should not have any uncovered expressions after you hit βRunβ β it should stay at the same color, indicating complete coverage. Furthermore, the server will run its own tests over your code, which means that you will not be able to submit code that does not work.
General note: Code quality will be graded. Write clean and tidy code. Consult the Style Guide, and if something is unclear, ask questions on the course forum.
The test form can be used to test that an expression is true, that an expression evaluates to some given value, or that an expressions raises an error with some expected text message. For example, the three kinds of tests are used in this example:
#lang pl
(: smallest : (Listof Number) -> Number)
(define (smallest l)
(match l
[(list)Β Β Β Β Β (error βsmallest βgot an empty listβ)]
[(list n)Β Β Β n]
[(cons n ns) (min n (smallest ns))]))
(test (smallest β(5 7 6 4 8 9)) => 4)
(test (zero? (smallest β(0 1 2 3 4))))
(test (smallest β()) =error> βgot an empty listβ)
In case of an expected error, the string specifies a pattern to match against the error message. (Most text stands for itself, β?β matches a single character and β*β matches any sequence of characters.)
Note that the =error> facility checks only errors that your code throws, not Racket errors. For example, the following test will not succeed:
(test (/ 4 0) =error> βdivision by zeroβ)
| The code for all the following questions should appear in a single .rkt file named |
| <your ID>_2 (e.g., 333333333_2 for a student whose ID number is 333333333). |
Β
1.Β Β BNF (SE)
- In class we have seen the grammar for AE β a simple language for βArithmetic Expressionsβ. Write a BNF for βSEβ: a similarly simple language of βString Expressionsβ. Valid βprogramsβ (i.e., words in the SE language) should go along the lines of pl expressions for Strings, with two exceptions: 1. Only digits 0,β¦,9 are allowed as valid characters within strings; 2. We will have two types of expressions that are not available in the pl language (see below βstringinsertβ and βnumber->stringβ type expressions). The valid operators that can be used in these expressions are string, string-length, and string-append, and also string-insert and number->string. It is also legal to have expressions of the form β<D>β, where <D> stands for a (finite) sequence of digits. Plain values in the language are characters (of digits) and natural numbers, thus the following are also valid expressions: a sequence of digits (such as, 347226) and an expression of the form #\v, where v is a digit.
Here, we do not care about implementing anything β neither the parser nor the evaluator. Thus, your code should be commented out. Still, it may be helpful to consider some future semantics that will help you understand the requirements. The operations β β, string, string-append,
string-insert, and number->string are considered expressions
that represent a string (they would return a string). The operation string-length, and digit sequences are considered expressions that represent a natural number (they would return a natural number).
Expression of the form #\v represent a character.
Note the following requirements for the grammar:
stringΒ is allowed with a sequence of any number of characters. string-append is allowed with a sequence of any number of expressions that represent strings. string-insert is allowed with an expression that represents a string, a character, and a natural number.Β Β
number->string is allowed with a natural number.
For example, some valid expressions in this language are:
β12344β
12
( string #\1 #\2 #\4 )
( string-append ( string #\1 #\2 #\4 ) β12β )
( string-insert β1357β #\4 66 )
( number->string 156879 )
( number->string ( string-length β0033344β ) )
( string-append β45β ( number->string ( string-length
β0033344β ) ))
( string-append )
( string-append ββ ( string-insert β1357β #\4 66 ) ββ )
#\3
but the following are invalid expressions:
| βa2bβ
12 13 4 67 ( string 124 ) ( string-append ( string-length β44β ) β12β ) ( string-insert β1357β 4 66 ) ( number->string β156879β ) ( string-append 33 44 66) #\3 #\4 #\32 #\q |
Β
NOTE: The use of ellipsis (ββ¦β) or β*β is not allowed here (find ways within the BNF framework to specify zero-or-more occurrences of a previous piece of syntax). Use π to specify the empty string. Β
Important remark: Β Your solution should only be a BNF and not a code in Racket (or in any other language). You cannot test your code!!! Indeed, your answer should appear inside a comment block (write the grammar in a #|β|# comment). Β
- Add to your BNF a derivation process for 3 different SE expressions, such that every operator (e.g., string-append, string-length, and
number->string) appears in at least one of these expressions. You may either provide a derivation tree or a series of replacements starting with <SE> and
(π)
ending with your string. Mark each derivation rule by an index (use βΒ Β Β Β Β Β β to state
=> that in a certain step, you have used rule number π of your BNF).
Β
2.Β Β Higher Order Functions
As you already know, lists are a fundamental part of Racket. They are often used as a generic container for compound data of any kind. It is therefore not surprising that Racket comes with plenty of useful functions that operate on lists. One of the most useful list functions is foldl: it consumes a combiner function, an initial value, and an input list. It returns a value that is created in the following way:
- For the empty list, the initial value is returned,
- For a list with one item, it uses the combiner function with this item and the initial value,
- For two items, it uses the combiner function with the first and the result of folding the rest (a one-item list),
In the general case, the value of foldl is:
(foldl f init (list x1 x2 x3 β¦ xn))
= (f xn (β¦ (f x3 (f x2 (f x1 init)))))
Note that foldl is a higher-order function, like map. Its type is:
(: foldl : (All (A B) (A B -> B) B (Listof A) -> B))
Use foldl together with (or without) map to define a sum-of-squares function which takes a list of numbers as input, and produces a number which is the sum of the squares of all of the numbers in the list. A correct solution should be a oneliner. Remember to write a proper description and contract line, and to provide sufficient tests (using the test form). You will need to do this for a definition of square too, which you would need to write for your implementation of sum-ofsquares.
A more detailed explanation on both functions can be found at the bottom of the assignment or here.
Β
Here is an example of a test that you might want to perform:
Β
Β
(test (sum-of-squares β(1 2 3)) => 14)
Β
Β
Β
3.Β Β PAE (and more H.O. functions)
- In this question, you are asked to write a function createPolynomial that takes as arguments a list of π numbers π0, β¦ , ππβ1 and returns as output a function. The returned function takes a number π₯0 and return the value of the polynomial π0 β π₯0 + β― + ππβ1 β π₯πβ1 at π₯0. To this end, you can use the built-in pl expt function taking two numbers π and π, and returning ππ.
The following should help you understand the task at hand:
> (createPolynomial β(1 2 4 2))
β : (Number -> Number)
#<procedure:polyX>
Β
(define p2345 (createPolynomial β(2 3 4 5)))
(test (p2345 0) =>
(+ (* 2 (expt 0 0)) (* 3 (expt 0 1)) (* 4 (expt 0 2)) (* 5
(expt 0 3))))
(test (p2345 4) =>
(+ (* 2 (expt 4 0)) (* 3 (expt 4 1)) (* 4 (expt 4 2)) (* 5 (expt 4 3))))
(test (p2345 11) => (+ (* 2 (expt 11 0)) (* 3 (expt 11 1)) (* 4 (expt 11 2)) (* 5 (expt 11 3))))
Β
Β
(define p536 (createPolynomial β(5 3 6)))
(test (p536 11) => (+ (* 5 (expt 11 0)) (* 3 (expt 11 1)) (* 6
(expt 11 2))))
Β
(define p_0 (createPolynomial β()))
(test (p_0 4) => 0)
Remark: all recursive calls should be in tail recursion.
You are given the following partial code. Use it as a basis for your full code. Donβt forget to add comments and tests.
(: createPolynomial : (Listof Number) -> <-fill in->)
(define (createPolynomial coeffs)
Β (: poly : (Listof Number) Number Integer Number ->
Number)
Β (define (poly argsL x power accum)
Β Β Β Β (if <-fill in->
Β Β Β Β Β Β Β <-fill in->
Β Β Β Β Β Β Β <-fill in-> )Β
Β (: polyX : Number -> Number)
Β (define (polyX x)
Β Β Β Β Γfill inβ)Β Β Γfill inβ)
Β
Β
Β
- We now move on to define a language PLANG that supports evaluating a polynomial on a sequence of points (numbers). You should base your solution on the interpreter we have written for the AE language. Specifically, your code should keep most of the definitions therein. The changes you do need to make are described next.
Β
- Write the BNF for the new language to allow for expressions of the
form {{ ππππ πͺπ πͺπ β¦ πͺπ} {π·π π·π β¦ π·π΅}} where all πΆπ and all ππ are valid AE expressions (and both π β₯ 1 and β β₯ 1).
See examples for valid expressions:
Β
β{{poly 1 2 3} {1 2 3}}β
β{{poly 4/5 } {1/2 2/3 3}}β
β{{poly 2 3} {4}}β
β{{poly 1 1 0} {-1 3 3}}β
Β Β Β Β β{{poly {/ 4 2}Β {- 4 1}} {{- 8 4}}}β
Β Β Β Β β{{poly {+ 0 1} 1 {* 0 9}} {{- 4 5} 3 {/ 27 9}}}β
Β
Also see examples for invalid expressions:
Β
β{{poly } {1 2 3} }β
β{{poly 4/5 } {1/2 2/3 3} {poly 1 2 4} {1 2}}β
β{{poly 2 3} {}}β
β{{poly 1 1 3} }β
Β
Β
Β
Β
You may use the following skeleton for your BNF:
#|
Β The grammar:
Β Β Β <PLANG> ::=Β
Β Β Β <AEs>Β Β ::=Β
Β Β Β <AE>Β Β Β ::=Β
Β |#
Β
- Write the parser for the new language. Use the following partial code as well the test examples provided below.
Β
(define-type PLANG
Β Β Β [Poly (Listof AE) <-fill in->])
Β
Β (define-type AE
Β Β Β [NumΒ Number]
Β Β Β [AddΒ AE AE]
Β Β Β [SubΒ AE AE]
Β Β Β [MulΒ AE AE]
Β Β Β [DivΒ AE AE])
Β
Β (: parse-sexpr : Sexpr -> AE)
Β ;; to convert s-expressions into AEs
Β (define (parse-sexpr sexpr)
Β Β Β (match sexpr
Β Β Β Β Β [(number: n)Β Β Β (Num n)]
Β Β Β Β Β [(list β+ lhs rhs) (Add (parse-sexpr lhs)Β
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β (parse-sexpr rhs))]
Β Β Β Β Β [(list β- lhs rhs) (Sub (parse-sexpr lhs)Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β (parse-sexpr rhs))]
Β Β Β Β Β [(list β* lhs rhs) (Mul (parse-sexpr lhs)Β
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β (parse-sexpr rhs))]
Β Β Β Β Β [(list β/ lhs rhs) (Div (parse-sexpr lhs)Β
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β (parse-sexpr rhs))]
Β [else (error βparse-sexpr βbad syntax in ~sβΒ Β Β Β Β Β Β Β Β Β Β sexpr)]))
Β Β
Β (: parse : String -> PLANG)
Β ;; parses a string containing a PLANG expressionΒ Β Β Β Β Β Β Β to a PLANG ASTΒ Β (define (parse str)
Β Β Β (let ([code (string->sexpr str)])
Β Β Β Β Β <-fill in->))
Β
(test (parse β{{poly 1 2 3} {1 2 3}}β)Β
Β Β Β Β => (Poly (list (Num 1) (Num 2) (Num 3))Β
Β Β Β Β Β Β Β Β Β Β Β Β Β (list (Num 1) (Num 2) (Num 3))))
(test (parse β{{poly } {1 2} }β)Β
Β Β Β Β =error> βparse: at least one coefficient isΒ Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β required in ((poly) (1 2))β)
(test (parse β{{poly 1 2} {} }β)Β Β Β Β Β Β =error> βparse: at least one point isΒ
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β required in ((poly 1 2) ())β)
Β
Β
iii. Β Β Β Β Write the evaluation process. In order to leave the AE eval unchanged (for the sake of keeping your work as simple as possible), we wrap it with an eval-poly function (which will be the core of the evaluator). We start with presenting the formal specification of the semantics:
Β
eval-poly({{ ππππ πͺπ πͺπ β¦ πͺπ} {π·π π·π β¦ π·π΅}}) =
β²(π(ππ£ππ(π1), β¦ , ππ£ππ(πβ))) where π is the polynomial defined by coefficients
(ππ£ππ(πΆ1), β¦ , ππ£ππ(πΆπ). That is, the expressions πͺπ πͺπ β¦ πͺπΒ Β are evaluated to coefficients and theΒ expressions π·π π·π β¦ π·π are evaluated to numbers on which we evaluate the polynomial.
Here are some possible tests:
Β
(test (run β{{poly 1 2 3} {1 2 3}}β)Β
=> β(6 17 34))
(test (run β{{poly 4 2 7} {1 4 9}}β)Β => β(13 124 589))
(test (run β{{poly 1 2 3} {1 2 3}}β)Β Β => β(6 17 34))
(test (run β{{poly 4/5 } {1/2 2/3 3}}β)Β
=> β(4/5 4/5 4/5))
(test (run β{{poly 2 3} {4}}β)Β => β(14))
(test (run β{{poly 1 1 0} {-1 3 3}}β)Β => β(0 4 4)))Β
(test (run β{{poly {/ 4 2} {- 4 1}} {{- 8 4}}}β)
=> β(14))
(test (run β{{poly {+ 0 1} 1 {* 0 9}} {{- 4 5} 3
{/ 27 9}}}β)
=> β(0 4 4))
Β
Use the following partial code as a basis for your code.
;; evaluates AE expressions to numbers
Β (define (eval expr)
Β Β Β (cases expr
Β Β Β Β Β [(Num n)Β n]
Β Β Β Β Β [(Add l r) (+ (eval l) (eval r))]
Β Β Β Β Β [(Sub l r) (- (eval l) (eval r))]
Β Β Β Β Β [(Mul l r) (* (eval l) (eval r))]
Β Β Β Β Β [(Div l r) (/ (eval l) (eval r))]))Β
Β (: eval-poly : PLANG ->Β Β <-fill in-> )
Β (define (eval-poly p-expr)
Β Β Β <-fill in-> )
Β
Β (: run : String -> (Listof Number))
Β ;; evaluate a FLANG program contained in a string
Β (define (run str)
Β Β Β (eval-poly (parse str)))
Β
HINT: You may want to use the procedure map (twice).Β See more about map below.
Β
On the procedures map and fold-l
ΧΧ€ΧΧ Χ§Χ¦ΧΧ map:
Χ§ΧΧ: Χ€Χ¨ΧΧ¦ΧΧΧ¨Χ proc ΧΧ¨Χ©ΧΧΧ lst Χ€ΧΧ: Χ¨Χ©ΧΧΧ Χ©ΧΧΧΧΧ ΧΧΧͺΧ ΧΧ‘Χ€Χ¨ ΧΧΧΧ¨ΧΧ ΧΧΧ Χ- lst β Χ©Χ ΧΧ¦Χ¨Χ Χ’βΧ ΧΧ€Χ’ΧΧͺ ΧΧ€Χ¨ΧΧ¦ΧΧΧ¨Χ proc Χ’Χ ΧΧ ΧΧΧ ΧΧΧΧΧ¨Χ ΧΧ¨Χ©ΧΧΧ lst. )ΧΧΧ‘ΧΧ¨ ΧΧΧ ΧΧΧ ΧΧΧΧ ΧΧΧͺΧ¨ β ΧΧ ΧΧΧ’Χ©Χ ΧΧ€ΧΧ Χ§Χ¦ΧΧ map ΧΧΧΧΧ
ΧΧΧ€Χ ΧΧΧ‘Χ€Χ¨ Χ¨Χ©ΧΧΧΧͺ β ΧΧ¦ΧΧ¨Χ ΧΧ©ΧΧΧ ΧΧ ΧͺΧΧ Χ ΧΧ ΧͺΧΧΧ§Χ§Χ ΧΧ©ΧΧΧΧ© ΧΧΧ( Β map proc lst β¦+) β list?) proc : procedure?Β Β lst : list?
Applies proc to the elements of the lsts from the first elements to the last. The proc argument must accept the same number of arguments as the number of supplied lsts, and all lsts must have the same number of elements. The result is a list containing each result of proc in order. Β :ΧΧΧΧΧΧΧͺ > (map add1 (list 1 2 3 4))
β(2 3 4 5)
> (map (lambda (x) (list x))
β(sym1 sym2 33)) β((sym1) (sym2) (33))Β :foldl ΧΧ€ΧΧ Χ§Χ¦ΧΧ
Χ§ΧΧ: Χ€Χ¨ΧΧ¦ΧΧΧ¨Χ proc, Χ’Χ¨Χ ΧΧͺΧΧΧͺΧ init ΧΧ¨Χ©ΧΧΧ lst Χ€ΧΧ: Χ’Χ¨Χ Χ‘ΧΧ€Χ )ΧΧΧΧͺΧ ΧΧΧ€ΧΧ‘ Χ©ΧΧΧΧΧ¨Χ ΧΧ€Χ¨ΧΧ¦ΧΧΧ¨Χ proc( Χ©Χ ΧΧ¦Χ¨ Χ’βΧ ΧΧ€Χ’ΧΧͺ ΧΧ€Χ¨ΧΧ¦ΧΧΧ¨Χ proc Χ’Χ ΧΧ ΧΧΧ ΧΧΧΧΧ¨Χ ΧΧ¨Χ©ΧΧΧ lst ΧͺΧΧ Χ©ΧΧΧΧ© ΧΧΧ©ΧͺΧ Χ Χ©Χ©ΧΧΧ¨ ΧΧͺ ΧΧ’Χ¨Χ Χ©ΧΧΧ©Χ Χ’Χ ΧΧ β ΧΧ©ΧͺΧ Χ ΧΧ ΧΧ§ΧΧ ΧΧ’Χ¨Χ ΧΧͺΧΧΧͺΧ ΧΧͺ ΧΧ’Χ¨Χ Χ©Χ init. )ΧΧΧ‘ΧΧ¨ ΧΧΧ ΧΧΧ ΧΧΧΧ ΧΧΧͺΧ¨ β ΧΧ ΧΧΧ’Χ©Χ ΧΧ€ΧΧ Χ§Χ¦ΧΧ foldl ΧΧΧΧΧ ΧΧΧ€Χ ΧΧΧ‘Χ€Χ¨ Χ¨Χ©ΧΧΧΧͺ β ΧΧ¦ΧΧ¨Χ ΧΧ©ΧΧΧ ΧΧ ΧͺΧΧ Χ ΧΧ ΧͺΧΧΧ§Χ§Χ ΧΧ©ΧΧΧΧ© ΧΧΧ(
Β
proc init lst β¦+) β any/c Β Β proc : procedure?
Like map, foldl applies a procedure to the elements of one or more lists. Whereas map combines the return values into a list, foldl combines the return values in an arbitrary way that is determined by proc. Β :ΧΧΧΧΧΧΧͺ > (foldl + 0 β(1 2 3 4))
10
> (foldl cons β() β(1 2 3 4))
β(4 3 2 1)
Β
Β
Β
Β
Β
Β








