On 12/09/2010 12:48 PM, Luke Jordan wrote:
I will look at for and in-range and spend some more time exploring the
built-ins. But I want to talk about the do-times solution, because that
was the first thing I tried, but I couldn't make it work. In chapter 11
expression arguments are applied to something that builds up a result
(as a list or an arithmetic operation). I don't understand how that
applies to what I'm trying to do here since I'm not building anything,
just calling it over and over and ignoring the result. Following what I
learned from chapter 11 the code would look something like this, which
doesn't make sense.
(define (do-times n expr)
(cond
[(< n 1) evaluate-expr-last-time]
[else ?? evaluate-expr (do-times (sub1 n) expr)]))
Let me rewrite that a little bit:
;; do-times : Nat (-> Void) -> Void
;; Applies the given thunk n times.
(define (do-times n action)
(cond [(zero? n) <BASE>]
[else
(<COMBINE> action (do-times (sub1 n) action)]))
What to put in the base case? Well, how many times should (do-times 0
action) apply the action? None. So <BASE> shouldn't involve action at
all. In Racket, the value that represents "nothing", "the commands have
been executed", etc is called the void value---but unlike in C and Java,
it actually is a value. You can get the void value by calling (void).
Note that the only thing special about the void value is that the REPL
printer doesn't print it; you could design this function using any value
to represent "I'm done, nothing else to report".
So now how to <COMBINE>? It should perform the action (represented by a
procedure of no arguments returning void) and then recur. The idiomatic
Racket way is to use 'begin':
(begin (action) (do-times (sub1 n) action))
But if you don't know 'begin', you can also do it using 'local' (or
'let', etc):
(local [(define do-not-care (action))]
(do-times (sub1 n) action))
Finally, it is still important to test such functions. It's harder, but
it's possible to test actions by their effect on data. (Mutation is
covered in Part VII.) Here's one way:
;; test-do-times : Nat -> boolean
;; Should always return #t, if do-times is working.
(define (test-do-times n)
(let ([counter 0])
(begin (do-times n (lambda () (set! counter (add1 counter))))
(= n counter))))
Or adapt that to your testing framework of choice (check-expect,
rackunit, etc).
Ryan
On Thu, Dec 9, 2010 at 13:08, Ryan Culpepper <[email protected]
<mailto:[email protected]>> wrote:
On 12/09/2010 11:51 AM, Luke Jordan wrote:
Here's a rookie question that stems from HtDP 29.3.2.
The idea is to test an expression a number of times while timing
it and
compare to another version of the same function. The expression
finds a
route in a vector (graph) from node 0 to node 4. The way I would do
this in C/Python is with a while loop, while the counter is not zero
execute the expression (ignore return value), and wrap it in the
timer.
In Racket I came up with:
(time (for-each
(lambda (dest) (find-route 0 dest Graph))
(make-list 1000 4)))
It seems unnecessarily tricky, but I couldn't think of a better
way. Am
I missing a piece? Does it only seem tricky because Racket is
my first
functional language.
To the student of functional programming:
You're right, it is unnecessary. You're using a list because you
know someone has already provided "loop" functions for lists. But
you just want to repeat an action N times---that's a natural number.
Refresh yourself on Section 11 (Natural Numbers) and design this
function:
;; do-times : Nat (-> Void) -> Void
;; Applies the given thunk N times.
To the aspiring Racketeer:
Racket has loop support for natural numbers, just not as a single
function like 'for-each'. Look at 'for' and 'in-range'.
Ryan
_________________________________________________
For list-related administrative tasks:
http://lists.racket-lang.org/listinfo/users