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.
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
In a larger program I'm writing out a small set (10^7) of numerical digits (0...9). This goes very slow with MIT-Scheme 10.1.10 on a 2.6GHz CPU, taking something like 2 minutes.
Probably I'm doing something wrong, like no buffering, but I'm pretty stuck after reading the reference guide. I reduced everything to the bare minimum:
(define (write-stuff port)
(define (loop cnt)
(if (> cnt 0)
(begin (display "0" port)
(loop (- cnt 1)))))
(loop 10000000))
(call-with-output-file "tmp.txt" write-stuff)
Any hints would be welcome...
[EDIT] To make things clear: the data-entries are unrelated to each other, and are stored in a 2D vector. They can be considered random, so I don't like to group them (it's either one-by-one or all-at-once). You can consider the data to be defined by something like
(define (data width height)
(make-initialized-vector width (lambda (x)
(make-initialized-vector height (lambda (x)
(list-ref (list #\0 #\1) (random 2)))))))
Apparently, the kernel/user-switch takes much time, so it's best to transform this to 1 string and write it out in 1 shot like #ceving suggested. Then it works fast enough for me, even though it's still 20s for 16MB.
(define (data->str data)
(string-append* (vector->list (vector-map vector->string data))))
(define dataset (data 4096 4096))
(call-with-output-file "test.txt" (lambda (p)
(display (data->str dataset) p)))
The problem is not that MIT-Scheme is so slow. The problem is, that you call the kernel function write excessively. Your program switches for every character from user mode to kernel mode. This takes much time. If you do the same in Bash it takes even longer.
Your Scheme version:
(define (write-stuff port)
(define (loop cnt)
(if (> cnt 0)
(begin (display "0" port)
(loop (- cnt 1)))))
(loop 10000000))
(call-with-output-file "mit-scheme-tmp.txt" write-stuff)
(exit)
The wrapper to run the Scheme version:
#! /bin/bash
mit-scheme --quiet --load mit-scheme-implementation.scm
On my system it takes about 1 minute:
$ time ./mit-scheme-implementation
real 1m3,981s
user 1m2,558s
sys 0m0,740s
The same for Bash:
#! /bin/bash
: > bash-tmp.txt
n=10000000
while ((n > 0)); do
echo -n 0 >> bash-tmp.txt
n=$((n - 1))
done
takes 2 minutes:
$ time ./bash-implementation
real 2m25,963s
user 1m33,704s
sys 0m50,750s
The solution is: do not execute 10 million kernel mode switches.
Execute just one (or at least 4096 times fewer):
(define (write-stuff port)
(display (make-string 10000000 #\0) port))
(call-with-output-file "mit-scheme-2-tmp.txt" write-stuff)
(exit)
And the program requires just 11 seconds.
$ time ./mit-scheme-implementation-2
real 0m11,390s
user 0m11,270s
sys 0m0,096s
This is the reason why buffering has been invented in the C library:
https://www.gnu.org/software/libc/manual/html_node/Stream-Buffering.html#Stream-Buffering
I'm currently learning to use some slightly more advanced features of scheme, and I've hit a road-block with lazy lists.
Basically, I'm trying to create an infinite, lazily generated list, and apply a lazy filter on it, and only take a single element. My hope was that this would consume very little memory: the filter looks at only one element at a time, and there's no need to store the previous entries. Here is my attempt at this:
(define lazy-inf-seq
(lambda (start next)
(delay (cons start (lazy-inf-seq (next start) next)))))
(define lazy-arithmetic-sequence
(lambda (start d)
(lazy-inf-seq start (lambda (v) (+ v d)))))
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([sequence seq])
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced) (lazy-filter pred (cdr forced)))]
[else (loop (cdr forced))]))))))
So, to be clear, a "lazy list" here is a procedure that, when (force)d, produces (head . tail), where head is one of the values on the list, and tail is the rest of the list (that needs to be forced in turn). I don't know if this is a "standard" lazy list in scheme or whatever, but it was the variant that made the most sense to me.
The (lazy-arithmetic-sequence a b) function produces (lazily) the infinite list a, a+b, a+2b, a+3b, ...
The lazy-filter function is the heart of the matter: it takes a predicate and a lazy list, and returns a lazy list with all the filtered elements. When forced, it goes through the input list finding the first element that should be included, and then returns that element consed with the lazy-filter of the rest of the list.
To test this out, I run this line:
(force (lazy-filter (lambda (v) (= v 1000000000)) (lazy-arithmetic-sequence 0 1)))
This is of course a rather pointless filter ("find the element with value one billion in this list from 0 to infinity"), but the point is to test the code out. The problem is that this consumes crazy amounts of memory. Within seconds its up to many gigabytes, and it shows no signs of slowing down, and I don't understand why.
I don't understand why the garbage collector doesn't reclaim the memory produced from the list. The loop in lazy-filter is tail-recursive, and there's no other references to the lazy list, so I feel like the GC should just gobble all that memory up. To make sure I even made a version that ran the garbage collector every iteration of the lazy-filter loop, and of course it didn't help.
My suspicion is that there's some reference hanging on to the head of the list that I'm not seeing. Like, the closure created by the delay in lazy-filter is somehow making the seq reference hang around, or something.
How can I rewrite this to not consume infinite amounts of memory?
I'm running Chez Scheme if that makes any difference, but I suspect that the problem is with me rather than the scheme implementation 🙂
Here's how to fix your problem:
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([sequence seq])
;; the following single line is added: ------ NB!
(set! seq sequence)
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced) (lazy-filter pred (cdr forced)))]
[else (loop (cdr forced))]))))))
I tried (force (lazy-filter (lambda (v) (= v 100000000)) (lazy-arithmetic-sequence 0 1))) in Racket, and it finishes up, though slowly, running in constant memory as reported by my OS, returning
'(100000000 . #<promise:unsaved-editor:12:4>)
Without the (set! seq sequence) the memory consumption reported by OS shots up by several gigabytes and then Racket reports it has run out of memory and the execution is aborted.
Some other re-writes of your code are found below, as are previous versions of this answer.
Trying your code in Racket's debugger, we get
forced and sequence are advancing along nicely, but seq is still at the start. And no wonder, nothing is changing it.
That's exactly what you suspected. A reference to the start of the sequence can not be released because seq is holding on to it until the result is found and returned (as the cons pair). For 100 elements it's not an issue, but for 1 billion it surely is.
Float loop up and out of lazy-filter and the problem seems to be gone:
This code transformation technique is known as lambda lifting.
The call to loop in lazy-filter becomes fully and manifestly tail because of it. Thanks to the tail call optimization the new call frame (for loop) can replace the old (for lazy-filter), which can now be discarded, together with its references into any data it held (here, seq).
The debugger snapshots show what's going on when the code is being debugged. Maybe without the debugging it is compiled differently, more efficiently. Maybe A Very Smart Compiler would in effect compile it by lambda lifting so the reference to seq could be relinquished, in the first code variant just as it is in the second. Looks like your Chez Scheme though compiles it just like Racket with debugging does (note, my version of Racket is old).
So it does seem like an implementation issue.
You will know for sure if you try the lambda-lifted code and see whether this fixes the problem:
(define (lazy-filter pred seq)
(delay (lazy-filter-loop pred seq)))
(define (lazy-filter-loop pred sequence)
(let ([forced (force sequence)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced)
(lazy-filter pred (cdr forced)))]
[else (lazy-filter-loop pred (cdr forced))])))
Although one could reasonably expect of Chez compiler to do this on its own. Maybe you are running interpreted code? Maybe you have the debugging information included? These are the questions to consider.
Another way to restructure your code is
(define lazy-filter
(lambda (pred seq)
(delay
(let loop ([forced (force seq)])
(cond [(null? forced) '()]
[(pred (car forced))
(cons (car forced)
(lazy-filter pred (cdr forced)))]
[else (set! seq (cdr forced))
(loop (force (cdr forced)))])))))
(the older version of the answer follows:)
Let's see what forcing your expressions entails. I will use shorter names for your variables and functions, for more visual and immediate reading of the code.
We'll use SSA program transformation to make a function's operational meaning explicit, and stop only on encountering a delay form.
You don't include your delay and force definitions, but we'll assume that (force (delay <exp>)) = <exp>:
(define (lz-seq s n) (delay (cons s (lz-seq (n s) n))))
(force (lz-seq s n))
=
(cons s (lz-seq (n s) n)) ;; lz-seq is a function, needs its args eval'd
=
(cons s (let* ([s2 (n s)]) (lz-seq s2 n)))
=
(let* ([s2 (n s)]
[lz2 (delay (cons s2 (lz-seq (n s2) n))) ])
(cons s lz2))
We've discovered that forcing your kind of lazy sequence forces its second element as well as the first!
(the following is incorrect:)
And this in fact exactly explains the behavior you're observing:
(force (lazy-filter (lambda (v) (= v 1000000000)) (lazy-arithmetic-sequence 0 1)))
needs to find out the second element of the filtered infinite stream before it can return the first cons cell of the result, but there's only one element in the filtered sequence, so the search for the second one never ends.
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...
I'm having some difficulty understanding how for loops work in scheme. In particular this code runs but I don't know why
(define (bubblesort alist)
;; this is straightforward
(define (swap-pass alist)
(if (eq? (length alist) 1)
alist
(let ((fst (car alist)) (scnd (cadr alist)) (rest (cddr alist)))
(if (> fst scnd)
(cons scnd (swap-pass (cons fst rest)))
(cons fst (swap-pass (cons scnd rest)))))))
; this is mysterious--what does the 'for' in the next line do?
(let for ((times (length alist))
(val alist))
(if (> times 1)
(for (- times 1) (swap-pass val))
(swap-pass val))))
I can't figure out what the (let for (( is supposed to do here, and the for expression in the second to last line is also a bit off putting--I've had the interpreter complain that for only takes a single argument, but here it appears to take two.
Any thoughts on what's going on here?
That's not a for loop, that's a named let. What it does is create a function called for, then call that; the "looping" behavior is caused by recursion in the function. Calling the function loop is more idiomatic, btw. E.g.
(let loop ((times 10))
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))
gets expanded to something like
(letrec ((loop (lambda (times)
(if (= times 0)
(display "stopped")
(begin (display "still looping...")
(loop (- times 1)))))))
(loop 10))
This isn't actually using a for language feature but just using a variation of let that allows you to easily write recursive functions. See this documentation on let (it's the second form on there).
What's going on is that this let form binds the name it's passed (in this case for) to a procedure with the given argument list (times and val) and calls it with the initial values. Uses of the bound name in the body are recursive calls.
Bottom line: the for isn't significant here. It's just a name. You could rename it to foo and it would still work. Racket does have actual for loops that you can read about here.