![]() |
![]() |
|
Due
03 (Fri) 23:59
Reading: Scott §§ 3.3.0–3.3.3 (scope), § 6.6 (tail-recursion).
Your name and the assignment-number must be in a comment at the start of the file, and your hardcopy must be stapled. All functions/data must include the appropriate steps1 of the-design-recipe.html. In particular, test cases alone might be worth half the credit for a function. Unless otherwise indicated, two test cases will suffice for most problems, if they are testing different situations.
(define positive-integer? (and/f integer? positive?)) (check-expect (positive-integer? 17) #t) (check-expect (positive-integer? -7) #f) (check-expect (positive-integer? 0) #f) (check-expect (positive-integer? "hello") #f) ; Note that `(integer? "hello")` is #f. (define non-empty-string? (and/f string? (λ(str) (not (string=? "" str)))) (check-expect (non-empty-string? "hello") #t) (check-expect (non-empty-string? "") #f) (check-expect (non-empty-string? 99) #f) |
Hint: A good, descriptive name for one of your parameters would be “keep?”.Use define instead of define/contract, but put the signature in a comment. Recall that the for the first argument of my-filter is itself a function, so your contract will look like (-> (-> ) (listof ) (listof ))! You can write
Tor
T?or
αas a type-variable.
Notice that several of the image-creating functions imported via (require 2htdp/image) are similar, in that they happen to take four arguments: two non-negative numbers v and w, a drawing mode (e.g. 'solid or #o162 (a transparency)) and a color. Two such examples are ellipse and rhombus.
(check-expect (shapes-in-a-row |
list-of-function; give its full signature2 (-> (listof (-> ) ).
Do not use define to create these functions; your answer should be of the form (shapes-in-a-row (list (lambda …) (lambda …))).
This is actually an example of theadaptor pattern: shapes-in-a-row expects functions that meet a certain interface (4 inputs), but the functions we have (star, pulled-polygon) need to be adapted to satisfy that interface. This can be easy (a couple lines, as above) in languages with anonymous functions and dynamic-typing (or good type inference); otherwise it might require writing entire classes and interfaces.
Note: Note that being tail-recursive is a property of a function’s source-code. The fact that a tail-recursive function can be optimized to not unnecessarily-allocate stack space is a compiler-implementation issue — albeit it’s what makes the concept of tail-recursion important.
Reading: Scott also discusses recursion and tail-recursion, in §6.6.1; (both 3rd and 4th eds).
#| /** Return the smallest number in a list. * @pre <code>!nums.isEmpty()</code> * @return the smallest number in `nums`. */ static Double myMin( List<Double> nums ) { // initialize our loop-variables: double minSoFar = nums.get( ); List<Double> numsRemaining = nums.subList( ,nums.size()); while ( ) { double a = numsRemaining.get(0); // corresponding to Scott’s variable `a` minSoFar = ( ? : ); numsRemaining = ; } return minSoFar; } |# |
Btw: The book’s starting-code calls (empty? (rest l)) — something not in the template. It’s a bit of a hack to stray from the template: Scott wants to avoid making a helper-function, but still return a sentinel-value answer for empty-lists.
However, when converting to tail-recursion, this difference ends up being moot: as you make a helper/wrapper function for the tail-recursion, that extra check disappears.
scheme vs racket: The book’s scheme code uses: car, cdr, null?, and #t. In racket, these names are (respectively): first, rest, empty?, and #true.
(check-expect (natnum->string/binary 0) "") ; Note that we remove (all) leading zeroes (!) (check-expect (natnum->string/binary 1) "1") (check-expect (natnum->string/binary 2) "10") (check-expect (natnum->string/binary 3) "11") (check-expect (natnum->string/binary 4) "100") (check-expect (natnum->string/binary 5) "101") (check-expect (natnum->string/binary 15) "1111") (check-expect (natnum->string/binary 16) "10000") (check-expect (natnum->string/binary (+ 1024 8 4)) "10000001100") (check-expect (natnum->string/binary #xA) "1010") ; hex literal (check-expect (natnum->string/binary #xFFFF) "1111111111111111") (check-expect (natnum->string/binary #xfeedBee) "1111111011101101101111101110") ; natnum->string/binary : natnum -> string ; Return the binary-numeral representing n (without any leading zeroes). ; Note that the numeral for zero, without leading zeros, is the empty-string! ; (define (natnum->string/binary n) (cond [(zero? n) ""] [(positive? n) (string-append (natnum->string/binary (quotient n 2)) (if (even? n) "0" "1"))])) |
Btw: This code doesn’t quite follow the design-recipe for natural-numbers, because it recurs on (quotient n 2) rather than (sub1 n). But it still works fine because it “reduces” the natnum to a smaller one. To reason about this code, you wouldn’t use straight-up mathematical induction; instead you'd call it “strong induction”.
This page licensed CC-BY 4.0 Ian Barland Page last generated | Please mail any suggestions (incl. typos, broken links) to ibarland ![]() |