Sorting three numbers in ascending order - scheme

I got home yesterday and decided to try and write a scheme program that would sort three numbers in ascending order. This is what I came up with:
(define a 3)
(define b 2)
(define c 1)
(define temp 0)
(cond
( (> a c) (set! temp c) (set! c a) (set! a temp))
( (> b c) (set! temp c) (set! c b) (set! b temp))
( (> a b) (set! temp b) (set! b a) (set! a temp))
( (> b c) (set! temp c) (set! b c) (set! b temp))
)
(display a)
(display b)
(display c)
Is that a functional way of solving the problem? What would you suggest?

Scheme has a builtin sort function that is actually faster in some cases than all the sort alorithms we use.
(sort < '(5 2 6))
returns
'(2 5 6)
The main problem that I see with your procedure is that you're only running a swap once. That's great if you can guarantee that one will always be in the middle of the other two, but I'm not so sure that it will always be the case. Also set! is kinda ugly and when I learned scheme my professor told me not to use it because it was resource intensive and there are better ways to do it. I would recommend putting them all in a list and then sorting them and pulling them out of the list if you want to do it that way.

Related

MIT-Scheme SICP Exercise_1.11 -- object #t is not applicable

This is my first post on StackOverflow. I have been working on Exercise 1.11 from SICP and feel I have a viable solution. In transferring from paper to Emacs I seem to have some syntax error that I am unaware of. I tried my best to double and triple check the parenthesis and solve it but the terminal is still giving me an 'object #t is not applicable' message. Could someone please point me in the right direction of how to fix the code so I can test its output properly?"
Exercise 1.11: A function f
is defined by the rule that:
f(n)=n
if n<3
, and
f(n)=f(n−1)+2f(n−2)+3f(n−3)
if n>=3
Write a procedure that computes f by means of a recursive process.
Write a procedure that computes f by means of an iterative process.
(define (f-recur n)
(if ((< n 3) n)
(+ (f(- n 1))
(* 2 (f(n-2)))
(* 3 (f(n-3)))))
(define (f-iter n)
(define (counter n)
(if (<= n 3) 0)
(- n 3))
(define (d n) (+ n (* 2 n) (* 3 n)))
(define (c n) (+ d (* 2 n) (* 3 n)))
(define (b n) (+ c (* 2 d) (* 3 n)))
(define (a n) (+ b (* 2 c) (* 3 d)))
(define (f a b c d counter)
(if ((> (+ counter 3) n) a)
(f (+ b (* 2 c) (* 3 d)) a b c (+ counter 1)))))
(cond ((= counter 0) d)
((= counter 1) c)
((= counter 2) b)
((= counter 3) a)
(else (f a b c d counter))))
I'm pretty sure SICP is looking for a solution in the manner of this iterative fibonnacci:
(define (fib n)
(define (helper n a b)
(if (zero? n)
a
(helper (- n 1) b (+ a b))))
(helper n 0 1))
Fibonacci is f(n)=f(n−1)+f(n−2) so I guess f(n)=f(n−1)+2f(n−2)+3f(n−3) can be made exactly the same way with one extra variable. Your iterative solution looks more like Fortran than Scheme. Try avoiding set!.

Is my implementation of SICP Exercise 1.3 going in the right direction?

Exercise 1.3 in SICP asks to define a procedure that takes 3 numbers as arguments and returns the sum of the squares of the 2 largest numbers. I think I've gotten it correct but I wasn't totally sure if I've covered all cases. My implementation is as follows:
(define (bigsq a b c)
(cond ((and (> a b) (> b c)) (+ (* a a) (* b b)))
((and (> a b) (not (> b c))) (+ (* a a) (* c c)))
((> c a) (+ (* b b) (* c c)))
(else (+ (* a a) (* b b))))
Is there a way to write those first 2 conditions as one, as well? Also any comments on efficiency are welcome as well.
For starters, we could use a helper procedure for implementing the sum just once:
(define (sum x y)
(+ (* x x) (* y y)))
Now, for the conditions: given that the order doesn't matter - (sum a b) is the same as (sum b a), there's only 4 cases to consider, and we can avoid repeating some of the comparisons by nesting ifs:
(define (sum-max a b c)
(if (>= a b)
(if (>= b c)
(sum a b)
(sum a c))
(if (>= a c)
(sum b a)
(sum b c))))

How to return a list from list of list in scheme?

I am trying to return from
'('(animal '(name a b c) '(age 1 2 3) '(family x y z)) only '(name age family). How do I do that? I was trying this:
(car(apply append(cons (cadr (car list)) '())))
but I get an error.
I am not sure the list you want to handle is:
'('(animal '(name a b c) '(age 1 2 3) '(family x y z)) or
'(animal (name a b c) (age 1 2 3) (family x y z))
The latter one makes more sense to me. Your (sub) problem is to return a list containing all first elements of sublists. You may need to use recursion. Something like:
(define get_list_of_first
(lambda (lol)
(if (null? lol) '()
(cons (car (car lol)) (get_list_of_first (cdr lol)))
)
)
)
This is a very basic example to learn Scheme. You need to use the above function to continue your assignment (I guess). Have fun.

How to use double do loop in Scheme?

I want to use "do" command to show(1 1)(1 2)(1 3)(2 1)(2 2)(2 3)(3 1)(3 2)(3 3)
and my code is below:
(lambda ( )
(define a 1)
(define b 1)
(do ((a 1 (+ a 1))) (= a 3)
(do ((b 1 (+ b 1))) (= b 3)
(display a b)
)))
But this only show3as the result. Did I do something wrong? How should I correct it?
To Michael Vehrs,
Thank a lot, it really works! But I'm still confusing about the exit condition. I tried to change the>in your code to=and it shows(1 1)(1 2)(2 1)(2 2). Is it because it stops when a = 3 so it won't print?
So "list" command can combine several variables. But how about "newline" command? I tried to remove it and it just add another () in the last.
Thank you for the answer. I'm a new Scheme learner trying to use it on TracePro. Do you have any tip(book, Youtube video, website) for me about learning Scheme? Any advise would help.
A do loop is just syntax sugar for a recursive function. You might as well get used to write it directly. Here is a way to do it with one named let with two variables and an accumulator.
(let loop ((a 3) (b 3) (acc '()))
(cond ((zero? a) acc) ; finished
((zero? b) (loop (sub1 a) 3 acc)) ; b finsihed, reduce a and reset b
(else (loop a (sub1 b) (cons (list a b) acc))))) ; reduce b and add to front of acc
; ==> ((1 1) (1 2) (1 3) (2 1) (2 2) (2 3) (3 1) (3 2) (3 3))
Notice this makes the result in reverse order so it's optimal for lists that always are created in reverse order since that only can add new element in front.
You mean:
(lambda ()
(do ((a 1 (+ a 1)))
((> a 3) (newline))
(do ((b 1 (+ b 1)))
((> b 3))
(display (list a b))))))
Your code has a number of problems: The exit condition for the do loop is incorrect (and makes your procedure return 3). display takes a single object and an optional port as arguments. Defining your variables a and b is unnecessary, since the do construct defines new loop variables anyway.

Scheme function won't print

Please tell me why the following Scheme function won't print the result. I'm using DrRacket.
#lang sicp
(define (sqr x) (* x x))
(define (sum_of_greatest_squares a b c)
(if(> a b)
(if(> a c)
(if(> b c)
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b))))
(+ (sqr a) (sqr c))
)
(if(> b c)
(if (> a c)
((+ (sqr a) (sqr b))(+ (sqr b) (sqr c)))
(+ (sqr c) (sqr b))))
))
(sum_of_greatest_squares 3 4 5)
Its plain to see that you haven't been very detail-oriented with your learning. Your code contains countless mistakes and you've allowed yourself to bring habits from other languages into your learning of scheme. DrRacket clearly shows there's a syntax error with your program, so that's a good place to start.
The sections I have bolded are missing an else expression
(define (sum_of_greatest_squares a b c)
(if(> a b)
(if(> a c)
(if(> b c)
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b))))
(+ (sqr a) (sqr c))
)
(if(> b c)
(if (> a c)
((+ (sqr a) (sqr b))(+ (sqr b) (sqr c)))
(+ (sqr c) (sqr b))))
))
The formatting of your code is bad and thus makes it harder to see where mistakes were made.
Moving along, here's another big mistake
((+ (sqr a) (sqr c))(+ (sqr a) (sqr b)))
You can't just put () wherever you want, like you can in some languages. () are used for procedure application in Lisp/Scheme/Racket.
Say a = 1, b = 2, and c = 3, the above line would be the equivalent of
((+ (sqr 1) (sqr 3))(+ (sqr 1) (sqr 2)))
((+ 1 9 )(+ 1 4 ))
(10 5)
The last line is (10 5) which says "apply the number 5 to the number 10" – which makes no sense.
You make the same mistake later in the code too. Try fixing up these problems first and then update your question.
ps: don't use snake_case names like sum_of_greatest_squares. Schemers typically would format that as sum-of-greatest-squares.
It's not immediately clear what your procedure is supposed to do anyway. My guess is that it's supposed to square the two largest inputs and then sum them.
You could do a huge hierarchy of if expressions to decide which two arguments to perform a computation with... but another way would be to always use the same two arguments to compute the result, but use if expressions to move the appropriate arguments into the correct place.
Consider this as a lateral alternative to your procedure
(define (sqr x) (* x x))
(define (sum-of-greatest-squares a b c)
(cond ((< a b) (sum-of-greatest-squares b c a))
((< b c) (sum-of-greatest-squares a c b))
(else (+ (sqr a) (sqr b)))))
This will always sum the squares of the two greatest numbers, but does so in a much cleaner way
Lastly, Jörg mentions that you're not actually printing anything anywhere. I know you mean to imply that DrRacket isn't showing the result of your program in the Interactions window. However, if you do want to explicitly print to the console, look at the display* and print* procedures

Resources