;;CS101, Spring 2013 ;; Lecture #12 ;; ;; * GENERATING RANDOM NUMBERS ;; ;; * USING A RANDOM NUMBER GENERATOR TO PRODUCE LISTS ;; ;; * ABSTRACTING FUNCTION PATTERNS FOR GENERAL APPLICABILITY ;; ;; * HIGHER-ORDER FUNCTIONS ;; - FILTER, MAP, APPLY, BUILD-LIST ; ; Every high-level programming language has a means to introduce ; unpredictability (also known as non-determinism) into a pro- ; gram, usually via a "random number generator". In Racket, the ; random function is used to generate random numbers between 0 ; and ONE LESS than the single numerical argument. ; ; "Random" numbers generated by a computer are formally known as ; "pseudo-random" to underscore the fact that no truly random ; activity is involved. ; ; Contract: (random pos-whole-number) -> 0...pos-whole-number-1 ; Header: (define random (lambda (x) ...)) ; Purpose: Generate a random number between 0 and (x - 1) ; NOTE THE MINUS IN THE LINE ABOVE!!! How would ; you call the random function if you wanted a ; random number between 1 and x? ; ; ; Ex 1: Write a function that returns the face-up value that ; ; results from rolling a 6-sided die. ; ; ; ; Contract: (die-roll) -> number (Note: zero-parameter function) ; ; HeaderL (define die-roll (lambda () ...)) ; ; Purpose: Generate a random number between 1 and 6 ; ; ; Pre-function test: ; (check-expect (and (>= (die-roll) 1) (<= (die-roll) 6)) #t) ; ; ; Function: ; (define die-roll ; (lambda () ;--------------- ; ; Ex 2: Write a function that returns the sum of throwing 2 ; ; 6-sided dice. ; ; ; ; Contract: (dice-pair-roll) -> number (Note: zero-parameter ; ; function) ; ; Header: (define dice-pair-roll (lambda () ..)) ; ; Purpose: Simulate the result of rolling 2 6-sided dice ; ; ; Pre-function test: ; (check-expect (and (>= (dice-pair-roll) 1) ; (<= (dice-pair-roll) 12)) #t) ; ; ; ; Function: ; (define dice-pair-roll ; (lambda () ;;;;;;;;;;;;;;;; RANDOMLY GENERATED LISTS ;;;;;;;;;;;;;;;;;; ; ; Ex 3: Write a function that generates a list of 100 random ; ; numbers, each between 1 and 200. ; ; ; ; Contract: (gen-ran-lon) -> lon ; ; Header: (define gen-ran-lon (lambda () ..)) ; ; Purpose: Generate a list of 100 random numbers, each between ; ; 1 and 200 ; ; ; ; Pre-function tests: It is hard to write meaningful tests when ; ; a function produces random results. ; ; ; ; Function: ; (define gen-ran-lon ; (lambda () ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; PATTERNS OVER FUNCTIONS and HIGHER-ORDER FUNCTIONS ; ; For one of the problems on homework 4, you wrote a function ; that filters the numbers out of a list of any data type: ; ; ; Contract: (filter-nums lox) -> lon ; ; Header: (define filter-nums (lambda (lx) ...)) ; ; Purpose: Return a list consisting of only the numbers in lx ; ; ; Pre-function tests: ; (check-expect (filter-nums '(1 a 2 b 3 c 4)) '(1 2 3 4)) ; (check-expect (filter-nums '()) '()) ; ; (define filter-nums ; (lambda (lx) ; (cond ; ; base case: return empty if list is empty ; ; ; recursive case 1: cons first onto call to rest ; ; predicate used here is number? ; ; ; recursive case 2: continue through list ; ; ; It may not surprise you to note that we could use any predicate on the ; first element in recursive case 1, and construct a list of only those ; items for which the predicate is true. ; ; For example, We could write a very similar function to produce only the ; symbols from the input list. ; ; A list of symbols (losy) is either: ; 1. empty, or ; 2. it's a (cons sym ls), where sym is a symbol and ls is a ; losy. ; ; ; Contract: (filter-syms lox) -> losy ; ; Header: (define filter-syms (lambda (lx) ...)) ; ; Purpose: Return a list consisting of only the symbols in lx ; ; ; Pre-function tests: ; (check-expect (filter-syms '(1 a 2 b 3 c 4)) '(a b c)) ; (check-expect (filter-syms '()) '()) ; ; (define filter-syms ; (lambda (lx) ; ; Read sections 21, intro and parts 21.1 and 21.2 out of HtDP 1st ed. ; ; FUNCTIONS AS PARAMETERS: ; ; One feature of languages like Racket is that functions can be ; passed as arguments to other functions. Functions that con- ; sume functions are known as HIGHER-ORDER functions. To abstract ; over the filter-nums and filter-syms functions, we could write ; a single function with an extra parameter to replace the boolean ; function called in recursive case 1 of each of these functions. ; ; To represent a function parameter type in a contract, use paren- ; theses and the following conventions: ; ; - If the function parameter consumes a single input and returns ; a boolean, the parameter should be written (X -> boolean) in ; the function contract. The X means that we don't know what type ; of input the function parameter will consume, but there is only ; one input parameter to this function. ; ; - If the function parameter consumes more than one argument and ; produces some type other than a boolean, the parameter could ; be written (X Y -> Y) in the contract, meaning that the output ; is of type Y and the inputs are of type X and Y. ; ;; The following function, filter-any, abstracts the filter-nums ;; and filter-syms functions by making the predicate function a ;; parameter. ; ; Contract: (filter-any (X -> boolean) lox) -> lox ; ; The (X -> boolean) above indicates a 1-parameter function that ; ; produces a boolean ; ; Header: (define filter-nums (lambda (pred lx) ...)) ; ; Purpose: Return a list consisting of only the Xs in lx for which (pred X) ; ; is true. ; ; ; Pre-function tests: ; (check-expect (filter-any number? '(1 a 2 b 3 c 4)) '(1 2 3 4)) ; (check-expect (filter-any symbol? '(1 a 2 b 3 c 4)) '(a b c)) ; (check-expect (filter-any string? '()) '()) ; (check-expect (filter-any string? '(1 a 2 b 3 c 4)) '()) ; (check-expect (filter-any boolean? '(1 a 2 b 3 c 4)) '()) ; ; (define filter-any ; (lambda (pred lx) ; (cond ; ; base case: return empty if list is empty ; ; ; recursive case 1: cons first onto call to rest. ; ; if (pred (first lx)) is true, (first lx) is consed onto output list ; ; created by calling filter-any recursively on pred and the rest of lx ; ; ; recursive case 2: continue through list. ; ; since (pred (first lx)) must be false at this point, just call ; ; filter-any recursively on pred and the rest of lx ; ; ; ; The filter pattern is so common that Racket provides a higher-order ; function called FILTER that consumes a function and a list and that ; returns a list containing only the elements of the list for which the ; function is true. ; ; Filter always returns a LIST that is <= to the input list in length. ; Filter may return a smaller list or an empty list. ; (check-expect (filter number? '(1 a 2 b 3 c 4)) '(1 2 3 4)) (check-expect (filter symbol? '(1 a 2 b 3 c 4)) '(a b c)) (check-expect (filter string? '(#t "jelly" a)) '("jelly")) ;;Write a function that consumes a list of anything and produces only the ;;even numbers in the list. Use the filter function. ;;Write a function that consume a list of strings and a number and produces ;;only the strings with length >= num. Use the filter function. ; ; Another common pattern when we write functions over lists is to apply ; some function to each element. This function is called MAP and it ; consumes a one-parameter function and a list and produces a list of ; the same length in which each value is the result of applying the ; function to each element in the input list. ; ; For example, to square every element in a list of numbers, we could ; type the following function invocation: (map sqr '(1 2 3 4 5)) ; ; The map function always produces a LIST that is the same length as ; its input list. ; (check-expect (map sqr '(1 2 3 4 5)) '(1 4 9 16 25)) (check-expect (map add1 '(1 2 3 4 5)) '(2 3 4 5 6)) ;; Write a function that consumes a list of numbers and produces a list ;; in which all even numbers are the same and all odd numbers are incre- ;; mented by one. Use the map function. ; ; Contract: (sum-sqrs lon) -> number ; ; Header: (define sum-sqrs (lambda (ln) ...)) ; ; Purpose: produce the sum of the square of each element in ln ; ; ; Pre-function tests: ; (check-expect (sum-sqrs '(1 2 3 4 5)) 55) ; (check-expect (sum-sqrs empty) 0) ; (check-expect (sum-sqrs '(1 2 1 2 1)) 11) ; ; (define sum-sqrs ; (λ (numlst) ; (local ; ;; first, declare a list that is the result of squaring every ; ;; item in numlst, using map ; ; ;; second, define a function to do recursion over the squared list ; ;; and add all the squared elements ; ; ;; third, call the local recursive function ; (sum-help sqrlst)))) ; ; The problem with the sum-sqrs function above is that, although ; we can use the map function to take one function (sqr) out of the ; recursive case, we still have to use recursion. ; ; There is a higher-order function that makes the process above ; even simpler. That function is called APPLY. The apply function ; consumes a function and a list and returns the result of applying ; the function to all the items on the list ; ; The apply function always produces a single element from a list. ; ; ; Contract: (sum-sqrs-v2 lon) -> number ; ; Header: (define sum-sqrs-v2 (lambda (ln) ...)) ; ; Purpose: produce the sum of the square of each element in ln ; ; ; Pre-function tests: ; (check-expect (sum-sqrs-v2 '(1 2 3 4 5)) 55) ; (check-expect (sum-sqrs-v2 '()) 0) ; (check-expect (sum-sqrs-v2 '(1 1 1 1 1)) 5) ; ; ; Function definition: ; (define sum-sqrs-v2 ; (λ (numlst) ; ; ; Map can also be applied to any number of equal-length lists (see in- ; class example) ; ;; Write a function that consumes 2 or more equal-length lists and ;; returns the list obtained by adding each of the first elements, ;; adding each of the second elements, and so on. ; ; There is also a built-in function called BUILD-LIST that takes a ; number n and a one-parameter function and which returns a list of ; length n in which the function has been applied to every number from ; 0 to n-1. ; (check-expect (build-list 5 (lambda (x) x)) '(0 1 2 3 4)) (check-expect (build-list 5 add1) '(1 2 3 4 5)) ; ; Any higher-order function can also consume an unnamed function, written ; using a lambda expression like those you wrote in lecture 3 and lab 2. ;