How to specify addition and subtraction in a function? - racket

I'm making a function that adds or subtracts x and y from the original coordinates.This function accepts a command ("left", "right", "up", "down") an (x, y) position, and a non-negative distance and produces a new point moving according to the command and distance.It's like "left" x-num, "right" x+num, "down" y+num, "up" y-num. For example, if you start at (2, 3), the command "left" 1 should produce (1, 3), whereas "down" 2.2 would produce (2, 5.2). Each part might works, but how can I add them into one function.
This is my code:
(define POSN-0 (make-posn 5 5))
(define POSN-1 (make-posn 10 10))
(define POSN-2 (make-posn 20 20))
(define (shift-left p)
(make-posn (- (posn-x p) num)
(posn-y p)))
(define (shift-right p)
(make-posn (+ (posn-x p) num)
(posn-y p)))
(define (shift-up p)
(make-posn (posn-x p)
(- (posn-y p) num)))
(define (shift-down p)
(make-posn (posn-x p)
(+ (posn-y p) num)))
How can I add all this in one function? Also, how can I define the add/subtract number?

After your edit, it's a little bit more clear what do you want, so here is my try.
Anyway, when you work with specific language (BSL in this case), you should mention that in the question. This will lead to answers more useful to you.
And see also this similar question- it seems that you're both attendees of the same course, so I suggest you to join forces and next time, post one well-thought question and not two similar.
(define (shift command p dist)
(cond
((string=? command "left")
(make-posn (- (posn-x p) dist)
(posn-y p)))
((string=? command "right")
(make-posn (+ (posn-x p) dist)
(posn-y p)))
((string=? command "up")
(make-posn (posn-x p)
(- (posn-y p) dist)))
((string=? command "down")
(make-posn (posn-x p)
(+ (posn-y p) dist)))))
Examples:
> (define p0 (make-posn 2 3))
> (shift "left" p0 1)
(make-posn 1 3)
> (shift "down" p0 2.2)
(make-posn 2 5.2)

You most certainly can have multiple parameters to a given function, and indeed you can see this with such built-in functions as + and -, as well as in the constructor (make-point) (which takes the four parameters as currently defined).
Speaking of which, what are the xp and yp members of the point structure for? A point in 2-dimensional space only need two coordinates. What are the other two for? Also, the (define-struct) form is deprecated in favor of the (struct) form, but that's not really important here.
As for how you would implement the 'commands', assuming that you are referring to the (command-point) function, you would have a parameter for the operation, another for the distance to move, and a case analysis (e.g., a (cond) form, or series of (if) forms, or in this instance, a (case) form) switching on the given command. Something like the following (untested code, you'll probably need to make adjustments):
(define (command-point p cmd dist)
(case cmd
(`left (make-point (- (point-x1 p) 1) (point-y1 p) (point-xp p) (point-yp p)))
(`right (make-point (+ (point-x1 p) 1) (point-y1 p) (point-xp p) (point-yp p)))
(`fwd (make-point (point-x1 p) (- (point-y1 p) 1) (point-xp p) (point-yp p)))
(`back (make-point (point-x1 p) (+ (point-y1 p) 1) (point-xp p) (point-yp p)))))
Note that this doesn't change the point passed through p; it instead generates a new point structure.
I hope this is what you were looking for, as to be honest your question wasn't entirely clear.

Related

Treating a part of program as data in Racket

I must say that I don't know really know how to call what I'm looking for, so perhaps the title isn't that accurate.
I have a program that plots some points. The generate-list function produces a list of n (x,y) coordinates and get-points produces another list that has every x (from (x,y)) divisible by n.
I can definitely call points how many times I need, but I'm trying to reduce the process by writing the points function only once).
#lang racket
(require plot)
(define (generate-list n)
(if (= n 0)
empty
(cons (list (random 0 100) (random 0 100))
(generate-list (- n 1)))))
(define (get-points lst n)
(if (empty? lst)
empty
(if (= (remainder (caar lst) n) 0)
(cons (car lst) (get-points (cdr lst) n))
(get-points (cdr lst) n))))
(plot (list
(axes 0 0)
(points (get-points (generate-list 1000) 2)
#:color 2)
(points (get-points (generate-list 1000) 3)
#:color 3)
(points (get-points (generate-list 1000) 4)
#:color 4)
(points (get-points (generate-list 1000) 5)
#:color 5)))
Bellow is an example that doesn't produce anything useful, but I'm looking for something that simplifies the code in a similar manner.
(plot (list
(axes 0 0)
(for ([i (in-range 2 5)])
(points (get-points (generate-list 1000) i)
#:color i))))
Of course any alternative that only writes the points function once would help a lot.
Try for/list instead of for there:
(plot (list
(axes 0 0)
(for/list ([i (in-range 2 5)])
(points (get-points (generate-list 1000) i)
#:color i))))
A for loop throws away the values the body-expression produces on each iteration, while the for/list loop puts them into a list, and returns the list so that all the points are included in the input to plot.
(By the way, this nested list is okay because plot allows a renderer-tree as input.)

Racket - arguments for procedure how to get all

I need to write procedure for calculation of weighted sum in follow functionality:
((weighted-sum 1) 5)
5
((weighted-sum 1/2 1/2) 3 1)
2
etc..
So far I did only how to get parameters for procedure:
(define (weighted-sum x . xn) (cons x xs))
(weighted-sum 2 3)
> '(2 3)
How to get ((weighted-sum 2 3) X X) parameters?
Thank you.
Your question doesn't have one easy answer. It sounds like you're supposed to write a function that accepts a sequence of weights, and returns a function that accepts a sequence of weights, and sums the products of the weights and the sums (by the way, stating this yourself would have been really helpful...).
1) Is this your design, or someone else's? I would not design this function this way.
2) You can write functions that return functions in a bunch of different ways. E.g.:
;; these all do the same thing.
;; they all have the type (number -> (number -> number))
(define a (lambda (x) (lambda (y) (+ x y))))
(define ((a x) y) (+ x y))
(define (a x)
(define (b y) (+ x y))
b)
So weighted-sum takes a variable number of values as parameters (let's call them ws) , and returns a new procedures that, in its turn, takes a variable number of parameters (vs) and does the calculation.
In racket, the for/fold construct comes in handy:
(define (weighted-sum . ws)
(lambda vs
(for/fold ((res 0)) ((i (in-list ws))
(j (in-list vs)))
(+ res (* i j)))))
or even
(define ((weighted-sum . ws) . vs)
(for/fold ((res 0)) ((i (in-list ws))
(j (in-list vs)))
(+ res (* i j))))
Alternatively, using a more classic foldl returning a named inner procedure:
(define (weighted-sum . ws)
(define (sub . vs)
(foldl
(lambda (i j res) (+ res (* i j)))
0
ws
vs))
sub)
For any of those:
> ((weighted-sum 1) 5)
5
> ((weighted-sum 1/2 1/2) 3 1)
2

SICP - Multiplication through addition

I am using the book SICP and attempting to solve this exercise:
1.2.4 Exponentiation
Exercise 1.18. Using the results of exercises 1.16 and 1.17, devise
a procedure that generates an iterative process for multiplying two
integers in terms of adding, doubling, and halving and uses a
logarithmic number of steps
I am trying to solve this with the following code:
(define (double x)
(+ x x))
(define (halve x)
(floor (/ x 2)))
(define (* a b)
(define (iter count accumulate)
(cond ((= count 1) accumulate)
((even? a) (iter (halve count) (+ accumulate (double b))))
(else empty)))
(iter a 0))
As you might see, I am trying to deal with even numbers first.
I am using the SICP wiki as my solutions-guide. They suggest some tests to see if the code works:
(* 2 4)
(* 4 0)
What I do not get is that my code passes on these two first tests, dealing only with even numbers.
However, when I try some big numbers which are multiples of two, the code fails. I checked the result using Python. For instance,
(IN PYTHON)
2**100
>> 1267650600228229401496703205376
2**98
>> 316912650057057350374175801344
a = 2**100
b = 2**98
a*b
>> 401734511064747568885490523085290650630550748445698208825344
When I use my function inside Dr. Racket with these values I get a different result:
(* 1267650600228229401496703205376 316912650057057350374175801344)
My result is: 63382530011411470074835160268800, which is wrong, as Python built-in functions suggest.
Why this is happening?
The recursive step seems wrong, and what's that empty doing there? also, what happens if b is negative? this solution should work:
(define (mul a b)
(define (iter a b acc)
(cond ((zero? b) acc)
((even? b) (iter (double a) (halve b) acc))
(else (iter a (- b 1) (+ a acc)))))
(if (< b 0)
(- (iter a (- b) 0))
(iter a b 0)))
For example:
(mul 1267650600228229401496703205376 316912650057057350374175801344)
=> 401734511064747568885490523085290650630550748445698208825344

Racket - comparing/analyzing two structures

So I have an assignment with the following criteria:
The definition of a function named euclidean-distance is given. This function computes the distance between two points in the xy-plane. The points are given as four separate numbers: x1, y1, x2, and y2.
Rewrite the function so that it takes two arguments, both of which are of type Posn, and run the same computation.
> (define the-origin (make-posn 0 0))
> (define some-point (make-posn 3 7))
> (euclidean-distance the-origin some-point)
#i7.615773105863909
> (euclidean-distance (make-posn 1 1) (make-posn 4 5))
5
My trouble here is that I'm not sure how to extract the information I need in order to compare square the differences and such. What I have so far:
(define (euclidean-distance posn1 posn2)
(sqrt (+ (sqr (- posn1-x posn2-x))
(sqr (- posn1-y posn2-y)))))
Not sure how to go about what I need to do.
Just use the accessor procedures of each position, like this:
(define (euclidean-distance posn1 posn2)
(sqrt (+ (sqr (- (posn-x posn1) (posn-x posn2)))
(sqr (- (posn-y posn1) (posn-y posn2))))))

How to calculate the sum of a digits of a number in Scheme?

I want to calculate the sum of digits of a number in Scheme. It should work like this:
>(sum-of-digits 123)
6
My idea is to transform the number 123 to string "123" and then transform it to a list '(1 2 3) and then use (apply + '(1 2 3)) to get 6.
but it's unfortunately not working like I imagined.
>(string->list(number->string 123))
'(#\1 #\2 #\3)
Apparently '(#\1 #\2 #\3) is not same as '(1 2 3)... because I'm using language racket under DrRacket, so I can not use the function like char->digit.
Can anyone help me fix this?
An alternative method would be to loop over the digits by using modulo. I'm not as used to scheme syntax, but thanks to #bearzk translating my Lisp here's a function that works for non-negative integers (and with a little work could encompass decimals and negative values):
(define (sum-of-digits x)
(if (= x 0) 0
(+ (modulo x 10)
(sum-of-digits (/ (- x (modulo x 10)) 10)))))
Something like this can do your digits thing arithmetically rather than string style:
(define (digits n)
(if (zero? n)
'()
(cons (remainder n 10) (digits2 (quotient n 10))))
Anyway, idk if its what you're doing but this question makes me think Project Euler. And if so, you're going to appreciate both of these functions in future problems.
Above is the hard part, this is the rest:
(foldr + (digits 12345) 0)
OR
(apply + (digits 1234))
EDIT - I got rid of intLength above, but in case you still want it.
(define (intLength x)
(define (intLengthP x c)
(if (zero? x)
c
(intLengthP (quotient x 10) (+ c 1))
)
)
(intLengthP x 0))
Those #\1, #\2 things are characters. I hate to RTFM you, but the Racket docs are really good here. If you highlight string->list in DrRacket and hit F1, you should get a browser window with a bunch of useful information.
So as not to keep you in the dark; I think I'd probably use the "string" function as the missing step in your solution:
(map string (list #\a #\b))
... produces
(list "a" "b")
A better idea would be to actually find the digits and sum them. 34%10 gives 4 and 3%10 gives 3. Sum is 3+4.
Here's an algorithm in F# (I'm sorry, I don't know Scheme):
let rec sumOfDigits n =
if n<10 then n
else (n%10) + sumOfDigits (n/10)
This works, it builds on your initial string->list solution, just does a conversion on the list of characters
(apply + (map (lambda (d) (- (char->integer d) (char->integer #\0)))
(string->list (number->string 123))))
The conversion function could factored out to make it a little more clear:
(define (digit->integer d)
(- (char->integer d) (char->integer #\0)))
(apply + (map digit->integer (string->list (number->string 123))))
(define (sum-of-digits num)
(if (< num 10)
num
(+ (remainder num 10) (sum-of-digits (/ (- num (remainder num 10)) 10)))))
recursive process.. terminates at n < 10 where sum-of-digits returns the input num itself.