Functional Programming Exercises a. 5 5 = 25 14.1 b. (( y. 3 + y + - - PDF document

functional programming
SMART_READER_LITE
LIVE PREVIEW

Functional Programming Exercises a. 5 5 = 25 14.1 b. (( y. 3 + y + - - PDF document

14 Functional Programming Exercises a. 5 5 = 25 14.1 b. (( y. 3 + y + z )2) = 3 + 2 + z = 5 + z c. ( v. ( w.w )( y ( z.z ))) 14.2 The results are the same. In part b, where there are two beta reductions, lazy evaluation gives a


slide-1
SLIDE 1

14

Functional Programming

Exercises

14.1

  • a. 5 ∗ 5 = 25
  • b. ((λy.3 + y + z)2) = 3 + 2 + z = 5 + z
  • c. (λv.(λw.w)(y(λz.z)))

14.2 The results are the same. In part b, where there are two beta reductions, lazy evaluation gives a different order: ((λx.x+2+z)3) = 3+2+z = 5+z. 14.3 Evaluate the following expressions using your Scheme interpreter: (a) #t (b) #f (c) a (d) ((b c) d e) (e) (b c) 14.4 (sum 1 2 3 4 5) = (+ 1 (sum 2 3 4 5)) = (+ 1 (+ 2 (sum 3 4 5))) = (+ 1 (+ 2 (+ 3 (sum 4 5)))) = (+ 1 (+ 2 (+ 3 (+ 4 (sum 5))))) = (+ 1 (+ 2 (+ 3 (+ 4 (+ 5 (sum ()))))) = (+ 1 (+ 2 (+ 3 (+ 4 (+ 5 0))))) ... = 15 14.5 (define (elements lst) (if (null? lst) 0 (if (list? (car lst)) (+ (elements (car lst)) (elements (cdr lst))) (+ 1 (elements (cdr lst))) 63

slide-2
SLIDE 2

64

  • 14. FUNCTIONAL PROGRAMMING

14.6 (m-expression ’(plus (times (variable a) (variable b)) (value 2)) ’((a 2) (b 4))) = (+ (* (m-expression (variable a) ((a 2) (b 4))) (m-expression (variable b) ((a 2) (b 4)))) (value 2)) = ... = (+ (* 2 4) 2) = (+ 8 2) = 10 14.7 Add the following to the case before the else in applyBinary: ((lt) (< leftval rightval)) ((le) (<= leftval rightval)) ((eq) (= leftval rightval)) ((ne) (not (= leftval rightval))) ((gt) (> leftval rightval)) ((ge) (>= leftval rightval)) 14.8 (define (m-assignment statement state) (let ((target (car statement)) (source (cdr statement))) (onion target (m-expression source state) state) )) 14.9 Add the following case before the else in m-expression: ((not) (not (m-expression (cadr expr) state))) 14.10 Below is a sketch of the essentials of a static type checker for Clite. First, assume the abstract syntax of program and declarations to be: ; Program = (declarations block) ; Declarations = ((v1 t1) (v2 t2) ...) ; where vi = variable identifier ; ti = type, i.e., int, bool, float, or char) Because Declarations already has the structure of a Clite TypeMap, a separate typing function to create a TypeMap is unnecessary. Then it is

  • nly necessary to implement the typeOf function and the various validity

functions V. For example: (define (v-program p) (let ((tm (car p)) (body (cadr p))) (and (v-decls tm) (v-stmt body tm)) )) (define (v-decls tm) (if (null? tm) #t (let ((d (caar tm)) (tail (cdr tm))) (if (isin? d tail) #f

slide-3
SLIDE 3

65 (v-decls tail) )))) (define (isin? id lst) (if (null? lst) #f (if (equal? id (caar lst)) #t (isin? id (cdr lst)) ))) Here, e.g., is the validity check for assignment: (define (v-assign s tm) (let ((target (cadr s)) (source (caddr s))) (and (isin? target tm) (v-expr source tm) (equal? (get target tm) (typeof source tm)) ))) Note that because a state and a type map have the same structure, we can use our get function on a TypeMap to retrieve a type. Here are the beginnings of a function typeof: (define (typeof e tm) (let ((kind (car e)) (opnd (cadr e))) (case kind ((value) (boolean? opnd)) ((variable) (get opnd tm)) ((plus minus times div) (typeof opnd)) (else bool) ))) 14.11 Most of this is summarized in Section 14.2.8, and many of the missing pieces are included in earlier exercises. The challenge here is to complete the implementation of the Clite lnterpreter in Scheme and then demon- strate its completeness by interpreting a variety of abstract Clite programs. 14.12 Using a caret to denote exponentiation, add the following case to diff: ((^) (if (equals x u) (list * v (list ^ x (list - v 1))) (list * v (list * (list ^ u (list - v 1)) (diff x u))))) 14.13 Here are the results:

  • a. > (diff ’x ’(+ (^ x 2) (+ (* 2 x) 1)))

(+ (* 2 (^ x (- 2 1))) (+ (+ (* 2 1) (* x 0)) 0))

  • b. > (diff ’x ’(/ (- (* 5 x) (* 2 y)) (+ (^ x 2) 1)))

(/ (- (* (+ (^ x 2) 1) (- (+ (* 5 1) (* x 0)) (+ (* 2 0) (* y 0)))) (* (- (* 5 x) (* 2 y)) (+ (* 2 (^ x (- 2 1))) 0))) (* (- (* 5 x) (* 2 y)) (+ (^ x 2) 1)))

slide-4
SLIDE 4

66

  • 14. FUNCTIONAL PROGRAMMING

14.14 The rules can be as extensive as desired; here will we consider only the two rules given as part of the problem, plus mutltiplfication by 0:

  • a. x + 0 = 0 + x = x

x ∗ 1 = 1 ∗ x = x x ∗ 0 = 0 ∗ x = 0

  • b. (define

(simpl expr) (if (not (list? expr)) expr (let ((op (car expr)) (u ((simpl cadr expr))) (v ((simpl caddr expr)))) (case

  • p

((+) (if (equal? u 0) v (if (equal? v 0) u (list ’+ u v)))) ((*) (if (or (equal? u 0) (equal? v 0)) 0 (if (equal? u 1) v (if (equal? v 1) u (list ’* u v))))) (else (list op u v) ))))

  • c. c1 + c2 = c3

where c3 = c1 + c2 c1 ∗ c2 = c4 where c4 = c1 ∗ c2

  • d. (define (constArith expr)

(if (not (list? expr)) expr (let ((u (constArith (cadr expr))) (v (constArith (caddr expr)))) (if (or (not (number? u)) (not (number? v))) expr (case (car expr) ((+) (+ u v)) ((*) (* u v)) (else (list (car expr) u v)) )))))

  • e. (define (simplify

expr) (let ((se (constArith (simpl expr)))) (if (equal? expr se) expr (simplify se) ))) 14.15

  • a. No solution prints.
  • b. The solution is: (4 2 5 3 1)
  • c. The solution is: (5 3 1 6 4 2). Backtracking is required.
slide-5
SLIDE 5

67 14.16 The Knights tour solution is in the file knight.scm in the ch14code directory. The function try expects the initial knight position to be given, e.g.: (try ((3 3))) The board is kept in reverse order; the current position of the knight is at the front of the list. Each knight position is given as a list of row, column entries; in the example above, the knight is at row 3, column 3. A move is kept as an integer from 1 to the length of trial, which is a list of knight moves relative to its current position. This implementation required a slight modification to the function trywh. 14.17 14.18 14.19 Evaluate the following expressions using your Haskell interpreter:

  • a. 3
  • b. Error: index (5) too large.
  • c. 1
  • d. [2,3,4,5]

14.20

  • a. [(”Jane”,1223345),(”Bob”,2771234),(”Allen”,2772345),(”Bob”,2770123)]
  • b. [(”Allen”,2772345),(”Bob”,2770123)]

14.21 deleteEntry :: Person -> Phonebook -> Phonebook deleteEntry p pb = [entry | entry <- pb, fst(entry) /= p] 14.22 elements [] = 0 elements (x:xs) = 1 + elements(xs) 14.23 The file Clite.hs in the ch14code directory is the skeleton of a Clite interpreter in Haskell. It contains the definitions in Section 14.3.8 as well as the following function. m (Block b) state | b == [] = state | otherwise = m (Block (tail b)) (m (head b) state) 14.24 The file Clite.hs in the ch14code directory is the skeleton of a Clite interpreter in Haskell (including int and bool values, but not char and float). It contains the following expansion of the eval function on page 403, along with a new apply function:

slide-6
SLIDE 6

68

  • 14. FUNCTIONAL PROGRAMMING

eval :: Expression -> State -> Value eval (Var v) state = get v state eval (Lit v) state = v eval (Binary op e1 e2) state = apply op (eval e1 state) (eval e2 state) apply :: Op -> Value -> Value -> Value apply "+" (Intval a) (Intval b) = (Intval (a + b)) apply "-" (Intval a) (Intval b) = (Intval (a - b)) apply "*" (Intval a) (Intval b) = (Intval (a * b)) apply "/" (Intval a) (Intval b) = (Intval (a ‘div‘ b)) apply "<" (Intval a) (Intval b) = (Boolval (a < b)) apply "<=" (Intval a) (Intval b) = (Boolval (a <= b)) apply "==" (Intval a) (Intval b) = (Boolval (a == b)) apply "!=" (Intval a) (Intval b) = (Boolval (a /= b)) apply ">=" (Intval a) (Intval b) = (Boolval (a >= b)) apply ">" (Intval a) (Intval b) = (Boolval (a > b)) apply "&&" (Boolval a) (Boolval b) = (Boolval (a && b)) apply "||" (Boolval a) (Boolval b) = (Boolval (a || b)) 14.25 The file Clite.hs in the ch14code directory contains the following ex- panded definition of Expression given on page 403, along with expanded definitions of eval and apply given above, and the new function applyUnary: data Expression = ... | Unary Op Expression deriving (Eq, Ord, Show) eval (Unary op e) state = applyUnary op (eval e state) applyUnary :: Op -> Value -> Value applyUnary "!" (Boolval a) = (Boolval (not a)) 14.26 Here is a summary: Let s = [("x", (Intval 5)), ("y", (Intval 3)), ("z", (Intval 1))] Then eval (Binary "+" (Var "y") (Lit (Intval 2))) s = apply "+" (eval (Var "y") s) (eval (Lit (Intval 2)) s) = apply "+" (get "y" s) (eval (Lit (Intval 2)) s) = apply "+" (Intval 3) (Intval 2) = Intval 3+2 = Intval 5 14.27 length [] = 0 length (w:ws) = 1 + length ws 14.28

  • a. fibSlow(25) delivers the result 75025 in about 20 seconds. fibSlow(50)

may still be running as you read this solution! The reason for this

slide-7
SLIDE 7

69 performance is that fibSlow(n) recalculates fibSlow(k) twice for every value of k < n. (b) This recalculation is eliminated by fibFast, which computes each number in the sequence only once, and then picks the last num- ber in the sequence at the end of this single chain of calls. Thus, fibFast(25) delivers the result 75025 immediately, and fibFast(50) delivers the result 125869025 immediately. 14.29 14.30 See the file simplify.hs in the directory ch14code, which implements the answer given in Exercise 14.14a. 14.31 Two Haskell files that solve modest Sudoku puzzles are given in the ch14code directory. These programs assume that the Sudoku game board squares are num- bered from left to right from 0 to 80. So row 0 = [0..9] and col 0 = [0,9,18,27,36,45,54,63,72]. Given that we can compute these, then the board values in row 0 are: [ board!!i | i <- row 0 ] Thus, we can use notElem to determine whether or not a trial move is safe. The basic strategy in these programs mimics that of the Eight Queens

  • problem. Instead of backtracking, we keep a list of boards and each board

has the same number of zeros (designating empty slots). Proceeding bottom-up and using set theory, we first substitute for a single board bd and a single zero index z, all values from 1 to 9, replicating the entire board each time that the substituion is safe: replaceOne z bd = [ replace z v bd | bd!!z == 0, v <- [1..9], v safe at position z ] Moving up a level, we substitute for position z for all boards b in the generated list bs. replaceAll z bs = [ replaceOne z b | b <- bs ] To solve for all zeros, we must use recursion: solve bs [ ] = bs solve bs z:zs = solve (replaceAll z bs) zs Thus, a puzzle is solved by the function: sudoku bd = solve [bd] (zeros bd)

slide-8
SLIDE 8

70

  • 14. FUNCTIONAL PROGRAMMING

There is only one remaining problem. The replaceAll function generates an extra [ ], giving [[[Int]]] instead of the desired [[Int]]. Two possible solutions for this problem are:

  • a. Combine replaceOne and replaceAll into one function.

This is shown by the function add in the program sudoku1.hs

  • b. Flatten the lists. This is shown in the program sudoku2.hs

To solve a sample puzzle, load one of these programs into the Haskell interpreter and then make the call: sudoku easy1 at the prompt. To solve other puzzles than easy1, change the argument to this call. 14.32 Some of the abstract syntax for Clite is modeled in Haskell the file Clite.hs, which has solutions to Exercises 14.23-14.25. Use Appendix A for a complete definition of the Clite type checking functions. The Clite type map can be modeled as follows: type Typemap = [(Variable, Type)] type Variable = String type Type = "int" | "boolean" | "char" | "float" The function typing needs Haskell definitions of the abstract concepts

  • f Declaration and Program, and can be defined as a function. All the

validity functions can be defined using these definitions together with a complete Haskell recursive data type definition of Clite abstract syntax. 14.33 Most of this is summarized in Section 14.3.8, along with the file Clite.hs which has solutions to Exercises 14.23-14.25. The challenge here is to complete the implementation of the Clite lnterpreter in Haskell and then demonstrate its completeness by interpreting a variety of abstract Clite

  • programs. Use Appendix A for a complete definition of the Clite meaning

functions. 14.34 This problem is reminiscent of a classical exercise in functional program- ming where students built a Scheme interpreter in Scheme. Usually a small subset of the Scheme function library was implemented, including functions cons, car, cdr, conditional expressions, and function definition and call. Fortunately, Scheme syntax is simple, and can be defined in just a few BNF rules. Tokens in Scheme are either parentheses, symbols, or num-

  • bers. Thus, the abstract syntax is also simple. Implementing the run-time

semantics of Scheme in Java requires the design of a read-eval-print loop. At each iteration, the user either calls or defines a Scheme function and

slide-9
SLIDE 9

71 then the system evaluates (or stores) it and displays the result, returning to the user with a prompt to begin the next iteration. Dealing with Haskell syntax for this exercise is a bit more cumbersome, since the syntax is more complex. Moreover, the TokenStream class will be more difficult to implement due to a greater variety of operators and reserved words. If Haskell is chosen as the language for this exercise, we recommend that students limit their attention to a subset that has only a few arithmetic operators and the ability to define recursive functions on

  • them. Anything more ambitious risks becoming tedious and unrewarding.
slide-10
SLIDE 10

72

  • 14. FUNCTIONAL PROGRAMMING