; CSE 341, Programming Langauges ; Lecture 13: Racket Introduction ; always make this the first (non-comment, non-blank) line of your file #lang racket ; not needed here, but a workaround so we could write tests in a second file ; see getting-started-with-Racket instructions for more explanation (provide (all-defined-out)) ; basic definitions (define three 3) (define five (+ three 2)) ; function call is (e1 e2 ... en): parens matter! ; basic function (define cube1 (lambda (x) (* x (* x x)))) ; many functions, such as *, take a variable number of arguments (define cube2 (lambda (x) (* x x x))) ; syntactic sugar for function definitions (define (cube3 x) (* x x x)) ; conditional (define (pow1 x y) (if (= y 0) 1 (* x (pow1 x (- y 1))))) ; currying (define pow2 (lambda (x) (lambda (y) (pow1 x y)))) ; sugar for currying (fairly new to Racket) (define ((pow2b x) y) (pow1 x y)) (define three-to-the (pow2 3)) (define eightyone (three-to-the 4)) (define sixteen ((pow2 2) 4)) ; need exactly these parens ; list processing: null, cons, null?, car, cdr ; we won't use pattern-matching in Racket (define (sum xs) (if (null? xs) 0 (+ (car xs) (sum (cdr xs))))) (define (my-append xs ys) ; same as append already provided (if (null? xs) ys (cons (car xs) (my-append (cdr xs) ys)))) (define (my-map f xs) ; same as map already provided (if (null? xs) null (cons (f (car xs)) (my-map f (cdr xs))))) (define foo (my-map (lambda (x) (+ x 1)) (cons 3 (cons 4 (cons 5 null))))) ; [first big difference from ML (and Java)] PARENS MATTER!! (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) ; base case calls the function 1 with zero arguments (define (fact-wrong1 n) (if (= n 0) (1) (* n (fact-wrong1 (- n 1))))) ; so why does this work (hint: it's not recursive ; and there is no type system): (define (fact-works1b n) (if (= n 0) (1) (* n (fact (- n 1))))) ; passing 5 arguments to if: =, n, 0, 1, (* ...) ; this is bad syntax ;(define (fact-wrong2 n) (if = n 0 1 (* n (fact-wrong2 (- n 1))))) ; calling n with zero arguments and also having an if ; this is not a legal definition: bad syntax ;(define fact-wrong3 (n) (if (= n 0) 1 (* n (fact-wrong3 (- n 1))))) ; calling multiply with three arguments, which would be fine ; except the second one is fact-wrong4 (define (fact-wrong4 n) (if (= n 0) 1 (* n fact-wrong4 (- n 1)))) ; calling fact-wrong5 with zero arguments, calling result of that ; with n-1 (define (fact-wrong5 n) (if (= n 0) 1 (* n ((fact-wrong5) (- n 1))))) ; treating n as a function of two arguments, passing it * (define (fact-wrong6 n) (if (= n 0) 1 (n * (fact-wrong6 (- n 1))))) ; [second big difference from ML (and Java)] Dynamic Typing!! ; dynamic typing: can use values of any type anywhere ; e.g., a list that holds numbers or other lists ; this function sums lists of (numbers or lists of (numbers or ...)), ; but it does assume it only encounters lists or numbers (else run-time error) (define (deep-sum1 xs) (if (null? xs) 0 (if (number? (car xs)) (+ (car xs) (deep-sum1 (cdr xs))) (+ (deep-sum1 (car xs)) (deep-sum1 (cdr xs)))))) ; this version does not fail on non-lists -- it treats them as 0 (define (deep-sum2 xs) (if (null? xs) 0 (if (number? (car xs)) (+ (car xs) (deep-sum2 (cdr xs))) (if (list? (car xs)) (+ (deep-sum2 (car xs)) (deep-sum2 (cdr xs))) (deep-sum2 (cdr xs)))))) ; better style: use cond instead of nested ifs ; sum3 is equivalent to sum1 above but better style (define (deep-sum3 xs) (cond [(null? xs) 0] [(number? (car xs)) (+ (car xs)(deep-sum3 (cdr xs)))] [#t (+ (deep-sum3 (car xs)) (deep-sum3 (cdr xs)))])) ; sum4 is equivalent to sum2 above but better style (define (deep-sum4 xs) (cond [(null? xs) 0] [(number? xs) xs] [(list? xs) (+ (deep-sum4 (car xs)) (deep-sum4 (cdr xs)))] [#t 0])) ; this function counts how many #f are in a (non-nested) list ; it uses the "controversial" idiom of anything not #f is true (define (count-falses xs) (cond [(null? xs) 0] [(car xs) (count-falses (cdr xs))] ; (car xs) can have any type [#t (+ 1 (count-falses (cdr xs)))]))