Assigning variables in Scheme without using set - scheme

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

Related

Scheme - How do I return a function?

This function is displaying the correct thing, but how do I make the output of this function another function?
;;generate an Caesar Cipher single word encoders
;;INPUT:a number "n"
;;OUTPUT:a function, whose input=a word, output=encoded word
(define encode-n
(lambda (n);;"n" is the distance, eg. n=3: a->d,b->e,...z->c
(lambda (w);;"w" is the word to be encoded
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26)) ))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w)) )
)))
You're already returning a function as output:
(define encode-n
(lambda (n)
(lambda (w) ; <- here, you're returning a function!
(if (not (equal? (car w) '()))
(display (vtc (modulo (+ (ctv (car w)) n) 26))))
(if (not (equal? (cdr w) '()))
((encode-n n)(cdr w))))))
Perhaps a simpler example will make things clearer. Let's define a procedure called adder that returns a function that adds a number n to whatever argument x is passed:
(define adder
(lambda (n)
(lambda (x)
(+ n x))))
The function adder receives a single parameter called n and returns a new lambda (an anonymous function), for example:
(define add-10 (adder 10))
In the above code we created a function called add-10 that, using adder, returns a new function which I named add-10, which in turn will add 10 to its parameter:
(add-10 32)
=> 42
We can obtain the same result without explicitly naming the returned function:
((adder 10) 32)
=> 42
There are other equivalent ways to write adder, maybe this syntax will be easier to understand:
(define (adder n)
(lambda (x)
(+ n x)))
Some interpreters allow an even shorter syntax that does exactly the same thing:
(define ((adder n) x)
(+ n x))
I just demonstrated examples of currying and partial application - two related but different concepts, make sure you understand them and don't let the syntax confound you.

scheme function to call a procedure n times

Does scheme have a function to call a function n times. I don't want map/for-each as the function doesn't have any arguments. Something along the lines of this :-
(define (call-n-times proc n)
(if (= 0 n)
'()
(cons (proc) (call-n-times proc (- n 1)))))
(call-n-times read 10)
SRFI 1 has a list-tabulate function that can build a list from calling a given function, with arguments 0 through (- n 1). However, it does not guarantee the order of execution (in fact, many implementations start from (- n 1) and go down), so it's not ideal for calling read with.
In Racket, you can do this:
(for/list ((i 10))
(read))
to call read 10 times and collect the result of each; and it would be done left-to-right. But since you tagged your question for Guile, we need to do something different.
Luckily, Guile has SRFI 42, which enables you to do:
(list-ec (: i 10)
(read))
Implementing tail-recursion modulo cons optimization by hand, to build the resulting list with O(1) extra space:
(define (iterate0-n proc n) ; iterate a 0-arguments procedure n times
(let ((res (list 1))) ; return a list of results in order
(let loop ((i n) (p res))
(if (< i 1)
(cdr res)
(begin
(set-cdr! p (list (proc)))
(loop (- i 1) (cdr p)))))))
This technique first (?) described in Friedman and Wise's TR19.

Iterative modulo by repeated subtraction?

I am trying to write an iterative procedure to do modulo arithmetic in scheme without using the built in procedures modulo, remainder or /. However I ran into a few problems while trying to write the code, which looks like this so far:
(define (mod a b)
(define (mod-iter a b)
(cond ((= b 0) 0)
((< b 0) (+ old_b new_b))))
(mod-iter a (- a b)))
As you can see, I ran into the problem of needing to add the original value of b to the current value of b. I am not sure how to go about that. Also, when i left the second conditional's answer to be primitive data (just to make sure the enitre procedure worked), I would get an "unspecified return value" error, and I'm not sure why it happens because the rest of my code loops (or so it seems?)
Thank you in advance for any insight to this.
When you define your mod-iter function with arguments (a b) you are shadowing the arguments defined in mod. To avoid the shadowing, use different identifiers, as such:
(define (mod a b)
(define (mod-iter ax bx)
(cond ((= bx 0) 0)
((< bx 0) (+ b bx))))
(mod-iter a (- a b)))
Note, this doesn't look like the proper algorithm (there is no recursive call). How do you handle the common case of (> bx 0)? You'll need something like:
(define (mod a b)
(define (mod-iter ax bx)
(cond ((= bx 0) 0)
((< bx 0) (+ b bx))
((> bx 0) ...))) ;; <- something here with mod-iter?
(mod-iter a (- a b)))
First if you don't want to capture a variable name, use different variable names in the inner function. Second i think the arguments are wrong compared to the built-in version. (modulo 5 6) is 5 and (modulo 6 5) is 1. Anyways here is a variation in logrirthmic time. That based on generating a list of powers of b (2 4 8 16 32 ...) is b is 2, all the way up to just under the value of a. Then by opportunistically subtracting these reversed values. That way problems like (mod (expt 267 34) 85) return an answer very quickly. (a few hundred primitive function calls vs several million)
(define (mod a-in b-in)
(letrec ((a (abs a-in))
(sign (if (< 0 b-in) - +))
(b (abs b-in))
(powers-list-calc
(lambda (next-exponent)
(cond ((> b a) '())
((= next-exponent 0)
(error "Number 0 passed as the second argument to mod
is not in the correct range"))
(else (cons next-exponent (powers-list (* b next-exponent))))))))
(let ((powers-list (reverse (powers-list-calc b))))
(sign
(let loop ((a a) (powers-L powers-list))
(cond ((null? powers-L) a)
((> a (car powers-L))
(loop (- a (car powers-L)) powers-L))
(else (loop a (cdr powers-L)))))))))

Not returning the answer i need

(define (checksum-2 ls)
(if (null? ls)
0
(let ([n 0])
(+ (+ n 1))(* n (car ls))(checksum-2 (cdr ls)))))
Ok, I have this code, its suppose to, if I wrote it right, the number (n) should increase by one every time it goes through the list, so n (in reality) should be like 1 2 3 4, but I want n to be multiplied by the car of the list.
Everything loads, but when the answer is returned I get 0.
Thanks!
If you format your code differently, you might have an easier time seeing what is going on:
(define (checksum-2 ls)
(if (null? ls)
0
(let ([n 0])
(+ (+ n 1))
(* n (car ls))
(checksum-2 (cdr ls)))))
Inside the let form, the expressions are evaluated in sequence but you're not using the results for any of them (except the last one). The results of the addition and multiplication are simply discarded.
What you need to do in this case is define a new helper function that uses an accumulator and performs the recursive call. I'm going to guess this is homework or a learning exercise, so I'm not going to give away the complete answer.
UPDATE: As a demonstration of the sort of thing you might need to do, here is a similar function in Scheme to sum the integers from 1 to n:
(define (sum n)
(define (sum-helper n a)
(if (<= n 0)
a
(sum-helper (- n 1) (+ a n))))
(sum-helper n 0))
You should be able to use a similar framework to implement your checksum-2 function.

How to create a function that multiplies all numbers between 1 and "x" with dotimes?

I'm making a function that multiplies all numbers between an 1 input and a "x" input with dotimes loop. If you please, check my function and say what's wrong since I don't know loops very well in Scheme.
(define (product x)
(let ((result 1))
(dotimes (temp x)
(set! result (* temp (+ result 1))))
result))
Use recursion. It is the way to do things in Scheme/Racket. And try to never use set! and other functions that change variables unless there really is no other choice.
Here's a textbook example of recursion in Scheme:
(define factorial
(lambda (x)
(if (<= x 1)
1
(* x (factorial (- x 1))))))

Resources