Scheme: solving task WITHOUT using if/cond? - scheme

So I've gotten rather simple task, in theory.
"Create a procedure where you take an integer as a parameter. If the integer is 0, return 0. If the integer is less than 0, return -1. If the integer is more than 0, return 1.
Solve this task without using if/cond(the only special forms allowed, are define, and, or)."
A very unpractical task, but a requirement for my course nonetheless. I've been stuck with this task for hours now, so I'd love some input!
Keep in mind that the procedure must return -1, 0 or 1. #t or #f are not good enough.

Both and and or are special versions of if. Eg.
(and a b) ; is the same as
(if a b #f)
(and a b c ...) ; is the same as
(if a (and b c ...) #f)
(or a b) ; is the same as
(if a
a ; though a is only evaluated once!
b)
(or a b c ...) ; is the same as
(if a
a ; though a is only evaluated once!
(or b c ...))
Notice that for 3 or more elements the result has and or or in it. You just apply the same transformation until you have something with just if.
If you want something like:
(if a 'x 'y)
You see that its obviously (or (and a 'x) 'y) since it turns into
(if (if a 'x #f)
(if a 'x #f)
'y)
Know that every value except #f is considered a true value. The basic method of doing this in "reverse" is knowing how and and or short circuits like if. If you need a special value returned instead of the result of a predicate you use and:
(and (null? x) 'empty-result)
If you need a false value to continue logic you use or
(or (and (null? x) 'empty-result)
(and (pair? x) 'pair-result))
If you need a default and have a or you just add it.
(or (and (null? x) 'empty-result)
(and (pair? x) 'pair-result)
'default-result)
If you happen to have and in the outer you need to wrap an or to get the default-result:
(or (and ...)
'default-result)
Good luck!

Here's a pretty simple implementation:
(define (signum n)
(or (and (zero? n) 0)
(and (positive? n) 1)
(and (negative? n) -1)))
Edit: I wrote my answer before I read Sylwester's post, but you should definitely read it for the theory of how this construction works.

Related

Taking the 'and' of a list by folding in Scheme

In the book Structure and Interpretation of Computer Programs
by H. Abelson and G. J. Sussman with J. Sussman,
the accumulation or fold-right is introduced in Section 2.2.3 as follows:
(define (accumulate op initial sequence)
(if (null? sequence)
initial
(op (car sequence)
(accumulate op initial (cdr sequence)))))
I tried to use this to take the and of a list of Boolean variables, by writing:
(accumulate and
true
(list true true false))
However, this gave me the error and: bad syntax in DrRacket (with #lang sicp),
and I had to do this instead:
(accumulate (lambda (x y) (and x y))
true
(list true true false))
Why? I believe it has something to do with how and is a special form,
but I don't understand Scheme enough to say.
Perhaps I'm just missing some obvious mistake...
You answered your own question: and is a special form (not a normal procedure!) with special evaluation rules, and accumulate expects a normal procedure, so you need to wrap it inside a procedure.
To see why and is a special form, consider these examples that demonstrate that and requires special evaluation rules (unlike procedures), because it short-circuits whenever it finds a false value:
; division by zero never gets executed
(and #f (/ 1 0))
=> #f
; division by zero gets executed during procedure invocation
((lambda (x y) (and x y)) #f (/ 1 0))
=> /: division by zero

How do I use and/or instead of if/cond?

I'm new to Scheme programming and I've gotten this task that I just can't find out how to work correctly. I'm supposed to define a procedure with one parameter (a number). If the number is positive I want 1 to be returned, -1 if the number is negative and 0 if it is 0, using only and/or. If and cond is not allowed. I only get #t or #f returned, but you see that's not what I want. Any help or pointers is appreciated
You can solve your problem if you look at the following equivalence, valid when every expj has a value different from #f:
(cond (test1 exp1) (or (and test1 exp1)
(test2 exp2) (and test2 exp2)
... ≡ ...
(testn expn) (and testn expn)
(else expn+1)) expn+1)
Since the function that gets the sign of a number can simply be written in this way:
(define (sign x)
(cond ((> x 0) +1)
((< x 0) -1)
(else 0)))
after applying the above equivalence, since every result is an integer, different from #f, this function becomes equal to the solution proposed also in another answer:
(define (sign x)
(or (and (> x 0) +1)
(and (< x 0) -1)
0))
So, which is the reason of the above equivalence? It depends on the fact that and evaluates its arguments in turn; as soon as one of them is #f, it stops by returning #f, otherwise returns its last argument (and this explains the single branches (and testj expj)); while or evaluates its arguments in turn; as soon as one of them is not #f, it stops by returning it, otherwise returns its last argument (and this explains the chain (or (and ...) (and ...) ... expn+1)).
(define test
(lambda (n)
(or (and (< n 0) -1)
(and (= n 0) 0)
1)))
Part of the trick is understanding that and, if everything evaluates to true, will return the last item it evaluated, while or will return the first thing that successfully evaluates to true. The other part is realizing that everything except for #f is considered "true."
The transformation of and is seen in the report but to not include the actual macros it's basically this:
; only one argument
(and a) ; ===>
a
; one of more
(and a b ...) ; ==>
(if a
(and b ...)
#f)
All arguments must be evaluate to a positive value and the last value is the result, else #f. It short circuits so when something is #f the rest of the expressions are never evaluated.
For or is like this:
(or a) ; ==>
a
(or a b ...) ; ==>
(let ((a-value a))
(if a-value
a-value
(or b ...)))
The first argument that does not evaluate to #f gets returned. If all values are #f the last #f will be the result.
Thus if you want:
(if a b c) ; ==>
(let ((tmpa a))
(or (and atmpa b)
(and (not atmpa) c)) ; not part only important if b can be #f
I use let to prevent evaluating the same expression several times. eg. if you had one that printed something like (begin (display "hello") #f) or it's an expensive calculation then it's necessary or else you can just substitute the variable with the expression. eg. the last would become:
(or (and a b)
(and (not a) c))
That transformed back with no temporary variables become:
(if (if a b #f)
(if a b #f)
(if (not a) c #f))
If b is #f value, then the result is #f because of the last if. Thus everytime a is true b is the result. Everytime it's false, c is the answer. Thus
(if a b c)
So imagine you want to return the first true value in a list.
(define (first-true lst)
(and (not (null? lst))
(car lst)
(first-true (cdr lst))))

Variadic Function in Scheme

I have to define a variadic function in Scheme that takes the following form:
(define (n-loop procedure [a list of pairs (x,y)]) where the list of pairs can be any length.
Each pair specifies a lower and upper bound. That is, the following function call: (n-loop (lambda (x y) (inspect (list x y))) (0 2) (0 3)) produces:
(list x y) is (0 0)
(list x y) is (0 1)
(list x y) is (0 2)
(list x y) is (1 0)
(list x y) is (1 1)
(list x y) is (1 2)
Obviously, car and cdr are going to have to be involved in my solution. But the stipulation that makes this difficult is the following. There are to be no assignment statements or iterative loops (while and for) used at all.
I could handle it using while and for to index through the list of pairs, but it appears I have to use recursion. I don't want any code solutions, unless you feel it is necessary for explanation, but does anyone have a suggestion as to how this might be attacked?
The standard way to do looping in Scheme is to use tail recursion. In fact, let's say you have this loop:
(do ((a 0 b)
(b 1 (+ a b))
(i 0 (+ i 1)))
((>= i 10) a)
(eprintf "(fib ~a) = ~a~%" i a))
This actually get macro-expanded into something like the following:
(let loop ((a 0)
(b 1)
(i 0))
(cond ((>= i 10) a)
(else (eprintf "(fib ~a) = ~a~%" i a)
(loop b (+ a b) (+ i 1)))))
Which, further, gets macro-expanded into this (I won't macro-expand the cond, since that's irrelevant to my point):
(letrec ((loop (lambda (a b i)
(cond ((>= i 10) a)
(else (eprintf "(fib ~a) = ~a~%" i a)
(loop b (+ a b) (+ i 1)))))))
(loop 0 1 0))
You should be seeing the letrec here and thinking, "aha! I see recursion!". Indeed you do (specifically in this case, tail recursion, though letrec can be used for non-tail recursions too).
Any iterative loop in Scheme can be rewritten as that (the named let version is how loops are idiomatically written in Scheme, but if your assignment won't let you use named let, expand one step further and use the letrec). The macro-expansions I've described above are straightforward and mechanical, and you should be able to see how one gets translated to the other.
Since your question asked how about variadic functions, you can write a variadic function this way:
(define (sum x . xs)
(if (null? xs) x
(apply sum (+ x (car xs)) (cdr xs))))
(This is, BTW, a horribly inefficient way to write a sum function; I am just using it to demonstrate how you would send (using apply) and receive (using an improper lambda list) arbitrary numbers of arguments.)
Update
Okay, so here is some general advice: you will need two loops:
an outer loop, that goes through the range levels (that's your variadic stuff)
an inner loop, that loops through the numbers in each range level
In each of these loops, think carefully about:
what the starting condition is
what the ending condition is
what you want to do at each iteration
whether there is any state you need to keep between iterations
In particular, think carefully about the last point, as that is how you will nest your loops, given an arbitrary number of nesting levels. (In my sample solution below, that's what the cur variable is.)
After you have decided on all these things, you can then frame the general structure of your solution. I will post the basic structure of my solution below, but you should have a good think about how you want to go about solving the problem, before you look at my code, because it will give you a good grasp of what differences there are between your solution approach and mine, and it will help you understand my code better.
Also, don't be afraid to write it using an imperative-style loop first (like do), then transforming it to the equivalent named let when it's all working. Just reread the first section to see how to do that transformation.
All that said, here is my solution (with the specifics stripped out):
(define (n-loop proc . ranges)
(let outer ((cur ???)
(ranges ranges))
(cond ((null? ranges) ???)
(else (do ((i (caar ranges) (+ i 1)))
((>= i (cadar ranges)))
(outer ??? ???))))))
Remember, once you get this working, you will still need to transform the do loop into one based on named let. (Or, you may have to go even further and transform both the outer and inner loops into their letrec forms.)

Function in Scheme that checks whether the length of a list is even

Hi I have edited the code for function in scheme that checks whether the length of a list is even.
(define even-length?
(lambda (l)
(cond
((null? l)#f)
((equal? (remainder (length(l)) 2) 0) #t)
(else #f))))
Is it corrrect?
You seem to have the syntax for if and cond all mixed up. I suggest referring to the language reference. if only has two clauses, and you don't write else for the else clause. (Hint: You shouldn't need an if for this function at all.)
Also, consider whether it makes sense to return null if the list is null; probably you want to return #t or #f instead.
Oh yeah, and rewrite your call of length to be a proper prefix-style Scheme function call.
The code is clearly wrong -- your %2 assuming infix notation, where Scheme uses prefix notation. The syntax of your if is wrong as well -- for an if, the else is implicit (i.e. you have if condition true-expression false-expression. In this case, you're trying to return #t from one leg and #f from another leg -- that's quite unnecessary. You can just return the expression that you tested in the if.
Edit: one other detail -- you should really rename this to something like even-length?. Even if I assume that it's a predicate, a name like even would imply to me that (even 3) should return #f, and (even 4) should return #t -- but in this case, neither works at all.
Edit2: Since mquander already gave you one version of the code, I guess one more won't hurt. I'd write it like:
(define (even-length? L) (even? (length L)))
I don't like using lower-case 'l' (but itself) much, so I've capitalized it. Since even? is built in, I've used that instead of finding the remainder.
Running this produces:
> (even-length? `(1 2 3))
#f
> (even-length? `(1 2 3 4))
#t
>
This is different from what you had in one respect: the length of an empty list is 0, which is considered an even number, so:
(even-length? `())
gives #t.
(define even-length? (lambda (l)
(even? (length l))))
Usage:
(even-length? '(1 2 3 4))
#t
(even-length? '(1 2 3 ))
#f
As others pointed out, there is indeed a predicate to check evenness of a number, so why not using it?
EDIT: I just saw Jerry Coffin wrote the same function witht the same example... Sorry for repeating :-)

Bounded variables and scope

I have tried to write a procedure that gets an integer as parameter and returns true if the number is a palindrome and false otherwise and it seems to be that there is a problem with changing a global parameter's value whithin an internal function block.
(define index 0)
(define (palindrome? x)
(if (= (lenght x) 1)
#t
(if (last_equal_first x)
(palindrome? (remove x))
#f)))
(define (lenght x)
(define index **(+ index 1))**
(if (= (modulo x (ten_power index)) x)
index
(lenght x)))
(define (last_equal_first x)
(if (= (modulo x 10) (modulo x (/ (ten_power (lenght x)) 10)))
#t
#f))
I would like to know what can I do about it
thanks!
Well, one problem is that you're redefining index after it's been used, in the length function. define doesn't really do what you want here - you want set!.
However, I think you'll find another bug when you try to call the length function more than once - you never set index to 0 after the first time, so I believe your length function will only work once.
However, this seems like it might be a homework assignment. Would you like clear instructions on fixing these problems, or would you like clues that lead you to understand the algorithm more?
What that (define ...) statement does in lenght is create a new variable called "index" that is more locally scoped than the "index" you defined at the top. That's only the superficial problem---more importantly, it looks like you're trying to write C code using Scheme. In a simple homework assignment like this, you should not need to use global variables, nor should you ever have to change a variable once it's created. Many programmers have trouble shifting how they think when first learning functional programming.
The way you've written lenght is not so much recursion as just a glorified while loop! There is no point to recursion if (lenght x) only calls (lenght x) again. For example, here's how I would write digits to count how many base-10 digits are in a number:
(define digits
(lambda (n)
(letrec ([digit-helper (lambda (n index)
(if (= (modulo n (expt 10 index)) n)
index
(digit-helper n (add1 index))))])
(digit-helper n 0))))
Notice how I never change a variable once it's been created, but only create new variables each time. Since I need to keep track of index, I created helper function digit-helper that takes two arguments to mask the fact that digit only takes one argument.

Resources