I'm doing some problems from Structure and Interpretation of Computer Programs
My case outputs #f as a valid result in the repl.it interpreter. I'm applying (and (not (max a b c)) (not (min a b c))) to get mid value.
I've tried rearranging the values for the mid function. The max and min functions work alright.
(define (max a b c)
(cond
((and(>= a b)(>= a c)) a)
((and(>= b a)(>= b c)) b)
((and(>= c a)(>= c b)) c)
))
(define (min a b c)
(cond
((and(<= a b)(<= a c)) a)
((and(<= b a)(<= b c)) b)
((and(<= c a)(<= c b)) c)
))
(define (mid a b c)
(and
(not (max a b c))
(not (min a b c))
))
(mid 10 8 6)
The output in the repl.it scheme interpreter is:
=> #f
I'd expect an error of some sort or a number value but this code returns a green #f so I'm assuming it means something is false? How can I fix this code to return a mid using conditional expressions?
I think it's worth thinking about how many tests you have to do to compute these things: to compute the extremum of three elements under any ordering operator you need to do no more than three comparisons:
(define (extremum/3 ordered? a b c)
;; find the extremum of three elements under ordered?
(cond ((and (ordered? a b) (ordered? a c)) a)
((ordered? b c) b)
(else c)))
And given this general function you can now define max/3 and min/3 easily:
(define (max/3 a b c)
(extremum/3 >= a b c))
(define (min/3 a b c)
(extremum/3 <= a b c))
Computing the mid point of three elements also requires no more than three tests:
(define (mid/3 a b c)
(if (>= a b)
(if (>= a c)
;; a is greatest, so we need to pick b or c
(if (>= b c) b c)
;; a is the mid point
a)
(if (>= a c)
;; a is the mid point
a
;; a is the minimum, pick b or c
(if (>= c b) b c))))
It's interesting to consider how many comparisons you need to find the mid point of n items.
I realized that I was passing a NOT from max AND min which is why it was evaluating false every time since there's always a false result from those expressions. I continued using comparisons to get the correct solution and adjusted the exceptions to take the mid to be a value which is either repeated three times or twice if it's not less than max or greater than min. The only thing that is unsettling is that I had to essentially express all conditions that are valid to isolate a mid number and couldn't explicitly define mid as NOT the max number AND NOT the min number. That being said there's got to be a better way to reduce these functions and eliminate the bulk of the comparisons...
(define (mid a b c)
(cond
((and(< a (max a b c))(> a (min a b c))) a)
((and(< b (max a b c))(> b (min a b c))) b)
((and(< c (max a b c))(> c (min a b c))) c)
(else (cond
((= (min a b c) (max a b c)) a)
((= a b) a)
((= a c) a)
((= b c) b)
))
))
Related
This is my first week using scheme, and I'm stuck on a simple problem. I want to write a function that does simple integer division. This is what I've written and I'm getting a bad syntax error. Any help on how to fix this and make the code work?
(define divisible-by
(lambda (a b)
(if (= a b)
(display #f))
)
(if (= (remainder a b) 0)
(display #t)
(else
(display #f))
)
)
Here is an answer that you won't be able to submit but which shows you how you might approach this.
I assume you are not allowed to simply use division, so one way to divide n by d, assuming n is a natural number and d is a non-zero natural number, is to repeatedly subtract d from n while incrementing a result, r, until you get a number which is less than d, which is the remainder. Here is that:
(define (div/rem n d)
;; Return the quotient and remainder of n by d
;;
;; You should perhas check they are naturals here, and that d is non-zero
;;
(define (div/rem-loop m r)
(if (< m d)
(values r m)
(div/rem-loop (- m d) (+ r 1))))
(div/rem-loop n 0))
There are more concise ways of writing this (named let is the obvious one).
I would like to return the nth cdr of a list. For example, I say
(nth-cdr 3 '(a b c d e)) and i would get (c d e) as output. I am not sure where I am going wrong with my code.
My approach is this. I will check if (= num 0) if it is, I will return the list. If not, I will recursively call nth-cdr and subtract 1 from num and cdr list
The code is this
(define arbitrary-cdr (lambda (num list)
(if (= num 0)
'()
(arbitrary-cdr (- num 1) (cdr list))
)))
However, I get this error when i try doing (arbitrary-cdr 3 ‘(a b c d e))
‘: undefined;
cannot reference an identifier before its definition
I am not sure what this means. When I say that, it means I hit the base case and would just like to return the list. I think my logic is correct though.
The first code that you posted was:
(define arbitrary-cdr
(lambda (num list)
(if (= num 0)
(list)
(arbitrary-cdr (- num 1) (cdr list)))))
The error that you received was:
scratch.rkt> (arbitrary-cdr 3 '(a b d c e))
; application: not a procedure;
; expected a procedure that can be applied to arguments
; given: '(c e)
The problem was that you used list as an argument to the arbitrary-cdr procedure; since Racket is a lisp-1, procedures do not have their own namespace, so this redefined list. With (list), and with list redefined the code attempted to call ((c e)), but (c e) is not a procedure.
This is a great example for why you should not use list or other built-in procedure identifiers as parameters in your own procedure definitions in Scheme or Racket. You can get away with this in Common Lisp, because Common Lisp is a lisp-2, i.e., has a separate namespace for functions.
With your updated code:
(define arbitrary-cdr
(lambda (num list)
(if (= num 0)
'()
(arbitrary-cdr (- num 1) (cdr list)))))
I don't get the error you report; maybe your code is not quite what you have posted. But, there is a mistake in the logic of your code. As it is, an empty list will always be returned:
scratch.rkt> (arbitrary-cdr 3 '(a b c d e f))
'()
The problem is that when the base case is reached you should return the input list, not an empty list. That is, given (arbitrary-cdr 0 '(a b c)), you want the result to be (a b c). This also means that your test case is wrong; (arbitrary-cdr 0 '(a b c d e)) --> '(a b c d e), and (arbitrary-cdr 3 '(a b c d e)) --> '(d e).
Here is your code rewritten, using xs instead of list to avoid the redefinition, and returning xs instead of an empty list when the base case is reached:
(define arbitrary-cdr
(lambda (num xs)
(if (= num 0)
xs
(arbitrary-cdr (- num 1) (cdr xs)))))
Sample interactions:
scratch.rkt> (arbitrary-cdr 0 '(a b c d e))
'(a b c d e)
scratch.rkt> (arbitrary-cdr 1 '(a b c d e))
'(b c d e)
scratch.rkt> (arbitrary-cdr 3 '(a b c d e))
'(d e)
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))))
Is there a way to specify bias in a random generator in lisp?
For instance if I had a range of numbers. How can I specify that the numbers in the first half of the range are 3× more likely than those in the last half?
I like Barmar's answer, and it handles arbitrary weights very well. However, it does require two calls to random, and that might be undesirable. Another approach would be to create a vector with elements that occur according to their intended frequency. E.g., if you have elements a and b that should be chosen with probability 1/3 and 2/3, then you can create an array (a b b) and select randomly from that.
(defun biased-generator (values weights)
(multiple-value-bind (total values)
(loop for v in values
for w in weights
nconc (make-list w :initial-element v) into vs
sum w into total
finally (return (values total (coerce vs 'vector))))
(lambda ()
(aref values (random total)))))
CL-USER> (defparameter *gen* (biased-generator '(a b) '(1 2)))
*GEN*
CL-USER> (loop for i from 1 to 100 collect (funcall *gen*))
(A A B A B A A B B A B B A A A B A A B A A A B A A A B B B B B A B B B B A A B
A B B A A A A B B B A A A A B A A B B B A A B B B A B B B B B B B B B B A B A
A A A B B B B A B A A B B A B A A B B B B B)
CL-USER> (let ((abs (loop for i from 1 to 10000 collect (funcall *gen*))))
(list (count 'a abs)
(count 'b abs)))
(3293 6707)
Do it in 2 steps:
First, select a random number in some arbitrary range, and determine if it's in the first 3/4 of the range. If it is, select a random number in the first half of the given range, otherwise select a random number in the second half:
(defun biased_random(low high) {
(let ((temp (random 1.0))
(middle (floor (+ high low) 2)))
(if (< temp 0.75)
(+ low (random (- middle low)))
(+ middle (random (- high middle)))))
I'm making a game, and I have this:
(define b "black piece") (define w "white piece")
(define (board)
(lambda (matrix)
(list ((b w b w b w b w)
(w b w b w b w b)
(b w b w b w b w)
(w b w b w b w b)
(b w b w b w b w)
(w b w b w b w b)
(b w b w b w b w)
(w b w b w b w b)))))
board makes a list with 8 lines and 8 columns of black and white pieces.
How do I access and change elements of the board? How do I do the procedure matrix with recursion?
first a few notes:
(define f (lambda (x) l ))
is the same as
(define (f x) l ))
You however are combining them with
(define (board) (lambda (matrix) l ))
which is the same as
(define board (lambda () (lambda (matrix) l )))
The distinction is important. The first two I have listed bind f to a function that take one parameter and return l. I'm guessing this is what you want to do. In the second two, you're binding board to a function that takes no parameters and returns a function that takes 1 parameter, matrix, (which it doesn't seem to do anything with), and returns a l.
second issue, (list ((b w....) ...)) isn't going to work because it will try to evaluate (b w ...). you need to have list in the function application position for each row of your board like so (list (list b w ...) (list w b ...) ...) in order for you code to even compile.
On to your question. link-ref is included in racket/base and is used for referencing elements in a list when you know the index into the list.
(list-ref 2 (list 'a 'b 'c 'd))
will return 'c. The index starts at 0. Since you have a list of lists, you will need to apply list-ref twice to retrieve a 'b or 'w.
As for changing it, well, you can't. As of r6rs, pairs (which make up lists) are immutable. The recommended way of doing things when possible is to return a new list with your change. you can use this somewhat inefficient version of list-set which returns a copy of the list with your new value at an index.
(define (list-set lis idx val)
(map (lambda (e i)
(if (= i idx) val e))
lis
(iota (length lis))))
In this case however, I would recommend switching to a different data structure more appropriate to the task at hand since you probably want O(1) access to the elements in the board. Look into vectors which behave much like lists but are used for constant lookups and updates. there is a built in vector-ref and vector-set! operations, which you should use instead of my above function.
Incase this is part of a larger problem and you're already using lists everywhere, you can use the vector->list and list->vector functions to go back and forth. Also, you can use mutable lists but don't.
Better still is the multidimensional array library offered in srfi/25, but that might be more complicated that you want to get.
The second part of your question was how to construct the board recursively. Well, here's a version using map.
(require (lib "1.ss" "srfi"))
(define (board)
(map (lambda (x)
(map (lambda (y)
(if (odd? (+ x y)) b w))
(iota 8)))
(iota 8)))
and here's a recursive version
(define (board)
(letrec ((board-helper
(lambda (x)
(if (eq? x 8) '()
(cons (row-helper x 0) (board-helper (+ 1 x))))))
(row-helper
(lambda (x y)
(if (eq? y 8) '()
(cons (if (odd? (+ x y)) b w) (row-helper x (+ 1 y)))))))
(board-helper 0)))