;; The first three lines of this file were inserted by DrRacket. They record metadata ;; about the language level of this file in a form that our tools can easily process. #reader(lib "htdp-beginner-reader.ss" "lang")((modname natnum-defn-taster) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f () #f))) (require 2htdp/image) ; A natnum is: ; - 0 OR ; - (add1 [natnum]) ; Examples of data meeting this datatype-defn: 0 (add1 0) (add1 (add1 0)) (add1 (add1 (add1 0))) ;;;;;; Template for any function handling a natnum: ; func-for-natnum : natnum -> ?? ; (define (func-for-natnum n) (cond [(zero? n) ...] [(positive? n) (... (func-for-natnum (sub1 n)))])) (check-expect (! 0) 1) (check-expect (! 1) 1) (check-expect (! 2) 2) (check-expect (! 3) 6) (check-expect (! 4) 24) (define (! n) (cond [(zero? n) 1] [(positive? n) (* n (! (sub1 n)))])) ; bullseye : natnum -> image ; return a picture of `n` concentric circles with decreasing sizes. (define (bullseye n) (cond [(zero? n) empty-image] [(positive? n) (overlay (circle (* n 10) 'outline 'blue) (bullseye (sub1 n)))])) (check-expect (bullseye 0) empty-image) (check-expect (bullseye 1) (circle 10 'outline 'blue)) (check-expect (bullseye 2) (overlay (circle 20 'outline 'blue) (circle 10 'outline 'blue))) (bullseye 4) ; write `list-ref` ; list-ref : natnum, list-of-α -> α ; Return the item at index `n` of `items` (0-based): ; pre-condition: `(< n (length items))` ; (define (my-list-ref n items) (cond [(zero? n) (first items)] [(positive? n) (my-list-ref (sub1 n) (rest items))])) (check-expect (my-list-ref 3 (cons 'a (cons 'b (cons 'c (cons 'd (cons 'e empty)))))) 'd) (check-expect (my-list-ref 2 (cons 'b (cons 'c (cons 'd (cons 'e empty))))) 'd) (check-expect (my-list-ref 1 (cons 'd (cons 'e empty))) 'e) (check-expect (my-list-ref 0 (cons 'd (cons 'e empty))) 'd) (check-expect (my-list-ref 0 (cons 'e empty)) 'e) #| (A student question) > For writing `list-ref`, do we need to use a while-loop-function > in order to retrieve the index value for the list that `my-list-ref` takes in? > From what I understand, if index is 0, we return the first item in the list, > but it’s the part about a number greater than 0 that has me confused. The answer to this lies in the data-defn / template for natural-number. I'll walk through it; for tl;dr, skip to the template at the end, and the example above. data def: A natural-number is: 0, OR (+ 1 [natural-number]) So we'll have a template which is a `cond` with two branches: ; func-for-natnum : natnum -> ?? (define (func-for-natnum n) (cond [(zero? n) ...] [(positive? n) ...])) But then the recipe suggests "if you have a variant which is a struct, pull out its fields". It LOOKS like that doesn't apply here, but actually it does: If (positive? n), then our definition tells us that n is built on some other natnum plus one. (That's like a struct containing a natnum inside it.) How do we "pull out that field" -- extract the natnum that `n` was created out of? Well, `n` is (add1 [natnum]) so that inner natnum is just `(- n 1)`! Btw, there is also `(sub1 n)`, for symmetry with `add1`. ...And if we pull out the "field" that was hidden inside `n`, it has type `natnum` (from the data-def'n). So what function might we call on it? The recipe suggests: Make the natural-recursive call! Thus we get: ; func-for-natnum : natnum -> ?? (define (func-for-natnum n) (cond [(zero? n) ...] [(positive? n) (... (func-for-natnum (sub1 n)))])) So just like we didn't need a while-loop to process a list, we don't need a while-loop to process all the numbers. [We will talk soon, about the connection between loop-constructs, and recursion, and how “tail recursion” is just a loop in disguise.] ...And, this all follows from the same ol' steps of the design recipe. Respect the structure of your data, and the code is often easy! |#