Hi Neil and Racket-users,<div><br></div><div>Thanks for the good inputs. Using your help I rewrote Euler #14:</div><div><br></div><div><div>; recursive function that returns the chain length of the passed argument</div><div>
; invoked as (collatz-length hash-table-instance n)</div><div>(define (collatz-length ht n)</div><div> (define colval (hash-ref ht n #f))</div><div> (unless colval</div><div> (if (even? n) </div><div> (set! colval (add1 (collatz-length ht (/ n 2))))</div>
<div> (set! colval (add1 (collatz-length ht (add1 (* 3 n))))))</div><div> (hash-set! ht n colval))</div><div> colval)</div><div><br></div><div>; same function with a different syntax</div><div>(define (collatz-length2 ht n)</div>
<div> (cond [(hash-ref ht n #f) => (lambda (colval) colval)]</div><div> [else</div><div> (define colval 0)</div><div> (if (even? n) </div><div> (set! colval (add1 (collatz-length2 ht (/ n 2))))</div>
<div> (set! colval (add1 (collatz-length2 ht (add1 (* 3 n))))))</div><div> (hash-set! ht n colval)</div><div> colval]))</div><div><br></div><div>; ProjectEuler problem #14 </div><div>(define (euler14)</div>
<div> (define ht (make-hash (list '(1 . 1))))</div><div> (define start-of-longest-chain 1)</div><div> (define longest-chain 1)</div><div> (for ([i (in-range 2 1000000)])</div><div> (define col-len (collatz-length2 ht i))</div>
<div> (when (< longest-chain col-len)</div><div> (set! longest-chain col-len)</div><div> (set! start-of-longest-chain i)))</div><div> (values start-of-longest-chain longest-chain))</div><div><br></div><b>The good news</b>: it is simpler, more idiomatic and faster</div>
<div><br></div><div><b>The bad news</b>: it still feels a little clunky. It has a lot of imperative statements and the memoization in the hash table feels too much like a side-effect to me.</div><div><br></div><div>Any more help?</div>
<div><br></div><div>Thanks again!</div><div>-Joe</div><div><br><div class="gmail_quote">On Mon, Apr 2, 2012 at 12:37 AM, Neil Van Dyke <span dir="ltr"><<a href="mailto:neil@neilvandyke.org">neil@neilvandyke.org</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Joe Gilray wrote at 04/02/2012 12:44 AM:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
1) [,,,]<div class="im"><br>
> (define ggg (make-hash (list '(1 4))))<br>
</div></blockquote>
<br>
Instead of '(1 4) , which is a list, you want a pair, '(1 . 4)) .<br>
<br>
If you're not yet familiar with pairs, you might want to soon take a detour from the numerical Project Euler problems, to play a bit with making your own pairs and lists. They're still pretty fundamental. Maybe try making some recursive procedures that build lists in different ways. (Don't use Hashes, nor the "do" form, nor "map", nor any of the "for"-something forms. Just you, recursive procedures, and "cons".)<div class="im">
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
2) My use of hash-has-key? feels clunky, Could I better use hash-ref? especially here:<br>
<br>
(if (hash-has-key? ht col)<br>
(let ([colval (hash-ref ht col)]) ...<br>
</blockquote>
<br></div>
Good eye. One way to do this is to use an optional argument to "hash-ref", to supply a default value that would never be returned if "col" were in "ht", and then to test against that default value. When possible, use #f for this default value, so that it works nicely as a Boolean, such as with "if".<br>
<br>
(let ((my-value-from-ht (hash-ref ht col #f)))<br>
(if my-value-from-ht<br>
[...do something with my-value-from-ht...]<br>
[...do something else...]))<br>
<br>
Even better, you can do this with "cond" "=>", like so:<br>
<br>
(cond ((hash-ref ht col #f)<br>
=> (lambda (my-value-from-ht)<br>
[...do something with my-value-from-ht...]))<br>
(else [...do something else...]))<br>
<br>
This code pattern with the "=>" thing looks cryptic to someone who's never seen it before, but it has a couple advantages: (1) you can't accidentally use "my-value-from-ht" in the ``do something else'' part; and (2) your code might be cleaner, if ``do something else'' part can become additional clauses for the "cond", rather than just the "else" clause.<br>
<br>
BTW, remember that "(lambda (my-value-from-ht) ...)" is just defining a procedure. In the "cond" example above, you might be able to put a variable identifier for a procedure instead, so "=> (lambda ...)" would look something like "=> my-proc", and somewhere else there would something like "(define (my-proc val) ...)". This is perhaps most useful when "my-proc" is more general than just that one "cond" clause.<br>
<br>
Neil V.<span class="HOEnZb"><font color="#888888"><br>
<br>
-- <br>
<a href="http://www.neilvandyke.org/" target="_blank">http://www.neilvandyke.org/</a><br>
<br>
____________________<br>
Racket Users list:<br>
<a href="http://lists.racket-lang.org/users" target="_blank">http://lists.racket-lang.org/<u></u>users</a><br>
</font></span></blockquote></div><br></div>