I'm learning Racket and I need some help. How do I run this function only 4 times instead of running it infinitely?
(define loop
(λ ()
(define delay (random 5))
(digital-write led1 HIGH)
(sleep delay)
(displayln delay)
(digital-write led1 LOW)
(sleep delay)
(loop)))
An easy way is to use for.
(define (do-it-once)
(define delay (random 5))
(digital-write led1 HIGH)
(sleep delay)
(displayln delay)
(digital-write led1 LOW)
(sleep delay))
(for ([n 4])
(do-it-once))
If you find you need to do this often, you can expand on soegard's for-based answer with a macro for making your code clearer:
(define-syntax-rule (repeat num-times body ...)
(for ([n num-times])
body ...))
(repeat 4
(define delay (random 5))
(digital-write led1 HIGH)
(sleep delay)
(displayln delay)
(digital-write led1 LOW)
(sleep delay))
This macro makes your intention explicit. This is useful for avoiding confusion when someone reading your code sees [n 4], because if your loop is complicated it might not be immediately apparent that you're only using the variable n for counting the loops. This is most definitely overkill if you only need it in one or two places however.
To answer this question in the general case, you could use an accumulator:
(define (loop arg)
(if (eq? arg 0)
"Done"
(loop (sub1 arg))))
(loop 4)
This will loop arg times. Every call will decrement arg by one. Once it is 0, you return whatever value you desired. Of course, this is a silly example as written, but demonstrates a general pattern you can use.
Note: the use of accumulator is a misnomer here, an accumulator usually accumulates a value over several calls...
Related
I am trying to create a global score in my scheme program and it will either increase by 1, decrease by 1 or not change for each iteration of my function. For example, I have this in my function when I want the score to increase by 1:
(set! score (+ score 1)))
I am able to do this using set! but I need a way to achieve it without using the set! operation. Any help would be appreciated!
The trick is to realise that you can replace something like this:
(define (my-game ...)
(let ([score 0])
(some-kind-of-looping-construct
...
(if <not-done>
(begin
(set! score <new-score-value>)
(continue-loop))
score))))
With something like this:
(define (my-game ...)
(define (loop ... score ...)
...
(if <not-done>
(loop ... <new-score-value> ...)
score))
(loop ... 0 ...))
In particular you can replace any kind of looping construct which repeatedly assigns to some variable by textually (but not actually) recursive calls to some function which repeatedly binds a variable.
To be concrete about this let's imagine we have a looping construct which looks like
(loop exit-fn form ...)
So loop is the loop construct, and exit-fn is the magic thing we call to exit the loop.
And I'll assume there is some function run-game-round which takes a round number and the current score, runs a round of the game and returns the new score.
So using this construct we can write the skeleton of some kind of game loop:
(let ((round 0)
(score 0))
(loop exit
(set! score (run-game-round round score))
(set! round (+ round 1))
(cond
[(> score 100)
(exit 'win)]
[(> round 100)
(exit 'lose)])))
And this is fairly horrible code.
But we can replace this code with this:
(begin
(define (run-game round score)
(cond [(> score 100)
'win]
[(> round 100)
'lose]
[else
(run-game (+ round 1)
(run-game-round round score))]))
(run-game 0 0))
And this code does exactly the same thing but there is no assignment anywhere.
No set!: We can input list or given number of args and use function recursive.
#lang racket
(define (play-game game-round-lst)
(local [(define (make-score s)
(cond
[(equal? s 'win) 1]
[(equal? s 'drew) 0]
[(equal? s 'lose) -1]))]
(apply + (map make-score game-round-lst))))
;;; TEST
(play-game '(lose win drew lose win)) ; 0
(play-game '(win lose drew win lose win lose)) ; 0
Use set! in local function.
In this method you can build new game without worry about lost state in each game.
#lang racket
(define (make-game)
(local [(define score 0)
(define (setup-score n)
(set! score (+ n score)))
(define (service-manager msg)
(cond
[(equal? msg 'win)
(setup-score 1)]
[(equal? msg 'drew)
(setup-score 0)]
[(equal? msg 'lose)
(setup-score -1)]
[(equal? msg 'show-score)
score]))]
service-manager))
;;; TEST
(define game1 (make-game))
(define game2 (make-game))
(game1 'win)
(game2 'win)
(game1 'drew)
(game2 'drew)
(game1 'lose)
(game2 'lose)
(game1 'show-score) ; 0
(game2 'show-score) ; 0
I am studying SICP and wrote two procedures to compute the sum of 1/n^2, the first generating a recursive process and the second generating an iterative process :
(define (sum-rec a b)
(if (> a b)
0
(exact->inexact (+ (/ 1 (* a a)) (sum-rec (1+ a) b)))))
(define (sum-it a b)
(define (sum_iter a tot)
(if (> a b)
tot
(sum_iter (1+ a) (+ (/ 1 (* a a)) tot))))
(exact->inexact (sum_iter a 0)))
I tested that both procedures give exactly the same results when called with small values of b, and that the result is approaching $pi^2/6$ as b gets larger, as expected.
But surprisingly, calling (sum-rec 1 250000) is almost instantaneous whereas calling (sum-it 1 250000) takes forever.
Is there an explanation for that?
As was mentioned in the comments, sum-it in its present form is adding numbers using exact arithmetic, which is slower than the inexact arithmetic being used in sum-rec. To do an equivalent comparison, this is how you should implement it:
(define (sum-it a b)
(define (sum_iter a tot)
(if (> a b)
tot
(sum_iter (1+ a) (+ (/ 1.0 (* a a)) tot))))
(sum_iter a 0))
Notice that replacing the 1 with a 1.0 forces the interpreter to use inexact arithmetic. Now this will return immediately:
(sum-it 1 250000)
=> 1.6449300668562465
You can reframe both of these versions so that they do exact or inexact arithmetic appropriately, simply by controlling what value they use for zero and relying on the contagion rules. These two are in Racket, which doesn't have 1+ by default but does have a nice syntax for optional arguments with defaults:
(define (sum-rec low high (zero 0.0))
(let recurse ([i low])
(if (> i high)
zero
(+ (/ 1 (* i i)) (recurse (+ i 1))))))
(define (sum-iter low high (zero 0.0))
(let iterate ([i low] [accum zero])
(if (> i high)
accum
(iterate (+ i 1) (+ (/ 1 (* i i)) accum)))))
The advantage of this is you can see the performance difference easily for both versions. The disadvantage is that you'd need a really smart compiler to be able to optimize the numerical operations here (I think, even if it knew low and high were machine integers, it would have to infer that zero is going to be some numerical type and generate copies of the function body for all the possible types).
I can use "while" loop in Racket with code from While Loop Macro in DrRacket
(define-syntax-rule (while-loop condition body ...)
(let loop ()
(when condition
body ...
(loop))))
However, I want to use break inside an infinite loop as follows:
(define (testfn)
(define x 5)
(while-loop #t ; infinite while loop;
(println x)
(set! x (sub1 x))
(when (< x 0)
(break)))) ; HOW TO BREAK HERE;
How can I insert break in above indefinite while loop? Thanks for your comments/answers.
You don't. Racket is in the Scheme family so all loops are actually done with recursion.
You break out of a loop by not recursing. Any other value would become the result of the form.
(define (helper x)
(displayln x)
(if (< x 0)
'return-value
(helper (sub1 x)))
(helper 5)
There are macros that makes the syntax simpler. Using named let is one:
(let helper ((x 5))
(displayln x)
(if (< x 0)
'return-value
(helper (sub1 x)))
Looking at your while-loop is just a macro that uses named let macro that turns into a recursive procedure.
If you instead of #t write an expression that eventually becomes false it stops. Like:
(while-loop (<= 0 x)
...)
Note that using set! to update variables in a loop is not considered good practise. If you are learning Racket try not to use set! or your new looping construct. Try using named let or letrec.
As mentioned in the accepted answer to the linked question, it's not recommended - at all! to do looping in this fashion. When using standard Scheme avoid imperative loops and prefer recursion (using helper procedures or a named let), or use iterations and comprehensions in Racket.
Also, break is not a standard Scheme construct. Consider rewriting the logic using a more idiomatic Racket that doesn't require explicit breaking and avoids the imperative style:
(define (testfn n)
(for [(x (in-range n -1 -1))]
(println x)))
(testfn 5)
=> 5
4
3
2
1
0
Is there a way to implement something like this
while time left
do something
where time is some variable set to x secs/minutes/hours in racket?
I could use some-constant to simulate time as in
(define (loop time)
(if (< time some-constant)
((do something)
(loop (- time 1)))
do-nothing))
but I would have to experiment to see what constant would give me one hour, etc.
Try the following:
(define (loop term-time)
(when (<= (current-seconds) term-time)
(begin <do something>
(loop term-time))))
Then you can invoke this with
(loop (+ (current-seconds) (* 60 60))) -- do it for one hour
If you just want to <do something> periodically, but doesn't want to do it at 100% CPU usage, in <do something>, you can include (sleep <secs>) to achieve this.
I know this is maybe an oddball idea, but I thought might as well give it a try to ask here.
I was experimenting in Racket about state representation without local variables.
The idea was defining a function that prints it's parameter value and if called again gives me another value. Since pure functions called with the same parameter always produce the same result, my workaround-idea got me the following.
(define (counter n)
(displayln n)
(λ () (counter (add1 n)))) ; unapplied lambda so it doesn't go in a loop
Then I devised a function to call counter and its resulting lambdas a certain number of times.
(define (call proc n)
(unless (zero? n)
(let ([x (proc)])
(call x (sub1 n)))))
Which results in this:
> (call (counter 0) 5)
0
1
2
3
4
5
What is the name for the concept applied here? Propably it's something trivial what you need in real applications all the time, but since I have no experience in that respect yet so I can't pinpoint a name for it. Or maybe I just complicated something very simple, but nonetheless I would appreciate an answer so I can look further into it.
Sorry if my question is not clear enough, but english is not my first language and to ask about things I have no name for makes me feel kinda uncertain.
You're using closures to save state: a lambda form stores the environment in which it was defined, and you keep redefining the procedure (called x in your code), so each time it "remembers" a new value for n.
Another way to do the same would be to let the procedure itself keep track of the value - in other words, counter should remember the current n value between invocations. This is what I mean:
(define (counter initial)
(let ((n (sub1 initial)))
(lambda ()
(set! n (add1 n))
n)))
In the above code, the first invocation of counter returns a new lambda that closes over n, and each invocation of that lambda modifies n and returns its new value. Equivalently, we could use Racket-specific syntax for currying and the begin0 special form to achieve the same effect:
(define ((counter n))
(begin0
n
(set! n (add1 n))))
Either way, notice how the procedure "remembers" its previous value:
(define proc (counter 0))
(proc)
=> 0
(proc)
=> 1
And we would call it like this:
(define (call proc n)
(unless (zero? n)
(displayln (proc))
(call proc (sub1 n))))
(call (counter 0) 5)
=> 0
1
2
3
4
Also notice that the above fixes an off-by-one error originally in your code - the procedure was being called six times (from 0 to 5) and not five times as intended, that happened because call invokes counter five times, but you called counter one more time outside, when evaluating (counter 0).