I am trying to write a simple program in Racket that prints 1 if the value of a is > 1, prints 0 if the value of a = 0 and -1 if a < 0 . I wrote the following but looks like it is not taking care of the third condition. Actually, I have not included the third condition so I don't know how to check for all three conditions using 'if' clause. A little guidance is appreciated.
I am new to Racket. My program is:
#lang racket
(define a 3);
(if (> a 0)
0
1)
-1
Thanks in advance.
The function you are looking for is already defined under the name sgn.
The reason your implementation doesn't work is that it is incomplete. You want:
(if (= a 0)
0
(if (< a 0)
-1
1))
Or just the better looking:
(cond
[(negative? n) -1]
[(positive? n) 1]
[else 0])
So how you describe it you have two consequences and one alternative. I would then have used cond:
(cond ((> a 0) 1)
((= a 0) 0)
(else -1)) ; if it's not greater or equal it has to be less than
With cond each term you can expect all previous to be false, thus the last test is not needed since if it's not greater or equal it has to be less than 0. This is exactly the same as writing:
(if (> a 0)
1
(if (= a 0)
0
-1))
The main difference is that it looks slightly better with cond. If you have a need for begin (side effects) then using cond would also be beneficial since it has implicit begin:
(define seen
(let ((hash (make-hash)))
(lambda (x)
(cond ((hash-ref hash x #f) #t)
(else (hash-set! hash x #t) #f)))))
The same with if:
(define seen
(let ((hash (make-hash)))
(lambda (x)
(if (hash-ref hash x #f)
#t
(begin
(hash-set! hash x #t)
#f)))))
Its the same but I feel cond wins since it's less indentation and more flat.
I'm a beginner CS student, but we started with Racket and this is how we would make this. Also, I'm just going by exactly what you say in your question "prints 1 if the value of a is > 1, prints 0 if the value of a = 0 and -1 if a < 0"
(cond
[(> a 1) 1]
[(= a 0) 0]
[(< a 0) -1])
Something else that I might add just purely as a CS student going by class standards, when we were writing functions that used intervals we always wrote an appropriate amount of check-expects to see if anything unexpected happens. I noticed that you have something happen when a > 1, a = 0, and everything below 0 would be = -1. So if you wrote a = 1 it would return with -1 if you had put "else" for anything that wasn't >1, = 0, or <0 . I don't know what you would want to happen if a = 1, but I thought I would just throw that out for good measure.
If you were to put in a = 1 with the cond written above it would just return with "cond: all question results were false".. Oki, now I'm done.
Related
CL-USER> (a-sum 0 3)
->> 6
I wrote this program :
(defun a-sum (x y)
(if (and (> x -1) (> y -1))
(do ((i 0 (1+ i))
(sum 0)
(num x))
((equal i (+ (- y x) 1)))
(setq sum (+ sum num))
(setq num (+ num 1))
sum)
(print " NOPE")))
put if I run it in the terminal it returns nil and not the answer stated above;
can someone help with the problem so it returns the value then Boolean.
DO,DO* Syntax
The entry for DO,DO* says that the syntax is as follows:
do ({var | (var [init-form [step-form]])}*)
(end-test-form result-form*)
declaration*
{tag | statement}*
The body is used as a list of statements and no intermediate value in this body is used as the result form of the do form. Instead, the do form evaluates as the last expression in result-form*, which defaults to nil.
(do ((i 0 (1+ i))
(sum 0)
(num x))
((equal i (+ (- y x) 1))
;;; RESULT FORMS HERE
)
(setq sum (+ sum num)) ;; (*)
(setq num (+ num 1)) ;; (*)
sum ;; (*)
)
All the expressions marked commented (*) above are used for side-effects only: the result of their evaluation is unused and discarded.
Problem statement
It is not clear to me what Σpi=ni means, and your code does not seem to compute something that could be expressed as that mathematical expression.
One red flag for example is that if (+ (- y x) 1) is negative (i.e. if y < x-1, for example y=1,x=3), then your loop never terminates because i, which is positive or null, will never be equal to the other term which is negative.
I would try to rewrite the problem statement more clearly, and maybe try first a recursive version of your algorithm (whichever is easier to express).
Remarks
Please indent/format your code.
Instead of adding setq statements in the body, try to see if you can define them in the iteration clauses of the loop (since I'm not sure what you are trying to achieve, the following example is only a rewrite of your code):
(do ((i 0 (1+ i))
(sum 0 (+ sum num)
(num x (1+ num))
(... sum))
Consider what value(s) a function returns. It's the value of the last form evaluated. In your case, that appears to be a do or maybe a setq or print (It's difficult to read as it's formatted now, and I don't have question edit privileges).
In short, the form that's returning the value for the function looks to be one evaluated for side-effects instead of returning a value.
(defun sum (n)
(if (n<0) 0 n-1) ;; if n<0, add 0. Else add the next smallest.
(sum (n-1)))
So far I come out with something like this but I am not sure how do I declare a variable to store the sum that I would like to return.
Note that you are implementing 1+2+...+m for m = n-1, which admits a simple formula:
(lambda (n)
;; You could inject n-1 on the formula to get n.(n-1)/2
;; (like in Vatine's answer), but here I just decrement
;; the input to show how to modify the local variable
;; and reuse the formula linked above to sum up-to m.
(decf n)
(if (minusp n)
0
(/ (* n (1+ n)) 2)))
An iterative version would work too, there is no need go recursive when doing simple loops:
(lambda (n) (loop :for x :below n :sum x))
Regarding your code:
Space matters1: n<0 is read as a symbol of name "N<0" (upcased by default). The same goes for n-1 which is a symbol named "N-1".
(n<0) will attempt to run the function named n<0. The same goes for (n-1).
Comparison: you can use (minusp n) or (< n 0).
Decrement: you can use (1- n) or (- n 1).
If what you wrote was correctly written, like this:
(defun sum (n)
(if (< n 0) 0 (- n 1))
(sum (- n 1)))
... there would still be issues:
You expect your (n-1) to actually decrement n but here the if only compute a value without doing side-effects.
You unconditionally call (sum (n-1)), which means: infinite recursion. The value returned by the preceding if is always ignored.
1: For details, look at constituent and terminating characters: 2.1.4 Character Syntax Types
Edit: zerop > minusp to check for negative numbers, fixed to fit OPs question
Was some time ago I used Lisp but if I recall right the last evaluation gets returned. A recursive solution to your problem would look like this:
(defun sum (n)
(if (<= n 0) 0 ;;if n is less or equal than 0 return 0
(+ (- n 1) (sum (- n 1))))) ;; else add (n-1) to sum of (n-1)
In Lisp, all comparator functions are just that, functions, so it needs to be (< n 0) and (- n 1) (or, more succinct, (1- n)).
You don't need to keep an intermediate value, you can simply add things up as you go. However, this is complicated by the fact that you are summing to "less than n", not "to n", so you need to use a helper function, if you want to do this recursively.
Even better, if you peruse the standard (easily available on-line, as the Common Lisp HyperSpec, you will sooner or later come across the chapter on iteration, where the loop facility does everything you want.
So if I needed to do this, I would do one of:
(defun my-sum (n)
(/ (* n (1- n)) 2))
or
(defun my-sum (n)
(loop for i below n
sum i))
If I absolutely needed to make it recursive, I would use something like:
(defun my-sum (n)
(labels ((sum-inner (i)
(if (< i 1)
0
(+ i (sum-inner (1- i))))))
(sum-inner (1- n))))
This is (almost) identical to defining a global function called sum-inner, which may be preferable for debugging purposes. However, since it is very unlikely that sum-inner would have any other use, I made it local.
(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1))))))
This program is designed to take a number and a function as inputs and do the following..
f(1) + f(2) + f(3)+ … + f(N).
An example input would be:
(generalized-triangular square 3)
The Error message:
if: bad syntax;
has 4 parts after keyword in: (if (= n 1) 1 (+ (input n) (generalized-triangular (- n 1))) input)
The error is quite explicit - an if form can only have two parts after the condition - the consequent (if the condition is true) and the alternative (if the condition is false). Perhaps you meant this?
(if (= n 1)
1
(+ (input n) (generalized-triangular input (- n 1))))
I moved the input from the original code, it was in the wrong place, as the call to generalized-triangular expects two arguments, in the right order.
For the record: if you need to execute more than one expression in either the consequent or the alternative (which is not the case for your question, but it's useful to know about it), then you must pack them in a begin, for example:
(if <condition> ; condition
(begin ; consequent
<expression1>
<expression2>)
(begin ; alternative
<expression3>
<expression4>))
Alternatively, you could use a cond, which has an implicit begin:
(cond (<condition> ; condition
<expression1> ; consequent
<expression2>)
(else ; alternative
<expression3>
<expression4>))
Literal answer
The code you posted in your question is fine:
(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1))))))
The error message in your question would be for something like this code:
(define generalized-triangular
(lambda (input n)
(if (= n 1)
1
(+ (input n) (generalized-triangular (- n 1)))
input)))
The problem is input. if is of the form (if <cond> <then> <else>). Not counting if itself, it has 3 parts. The code above supplies 4.
Real answer
Two tips:
Use DrRacket to write your code, and let it help you with the indenting. I couldn't make any sense of your original code. (Even after someone edited it for you, the indentation was a bit wonky making it still difficult to parse mentally.)
I don't know about your class, but for "real" Racket code I'd recommend using cond instead of if. Racket has an informal style guide that recommends this, too.
here's the tail-recursive
(define (generalized-triangular f n-max)
(let loop ((n 1) (sum 0))
(if (> n n-max)
0
(loop (+ n 1) (+ sum (f n))))))
Since you're using the racket tag, I assume the implementation of generalized-triangular is not required to use only standard Scheme. In that case, a very concise and efficient version (that doesn't use if at all) can be written with the racket language:
(define (generalized-triangular f n)
(for/sum ([i n]) (f (+ i 1))))
There are two things necessary to understand beyond standard Scheme to understand this definition that you can easily look up in the Racket Reference: how for/sum works and how a non-negative integer behaves when used as a sequence.
I need to make something like this but in ACL2:
for (i=1; i<10; i++) {
print i;
}
It uses COMMON LISP, but I haven't any idea how to do this task...
We can't use standard Common Lisp constructions such as LOOP, DO. Just recursion.
I have some links, but I find it very difficult to understand:
Gentle Intro to ACL2 Programming
The section "Visiting all the natural numbers from n to 0" in A Gentle Introduction to ACL2 Programming explains how to do it.
In your case you want to visit numbers in ascending order, so your code should look something like this:
(defun visit (n max ...)
(cond ((> n max) ...) ; N exceeds MAX: nothing to do.
(t . ; N less than or equal to MAX:
. n ; do something with N, and
.
(visit (+ n 1) max ...) ; visit the numbers above it.
.
.
.)))
A solution that uses recursion:
> (defun for-loop (from to fn)
(if (<= from to)
(progn
(funcall fn from)
(for-loop (+ from 1) to fn))))
;; Test
> (for-loop 1 10 #'(lambda (i) (format t "~a~%" i)))
1
2
3
4
5
6
7
8
9
10
NIL
(defun foo-loop (n)
(cond ((zp n) "done")
(t (prog2$ (cw "~x0" n)
(foo-loop (1- n)))))
(foo-loop 10)
You can redo the termination condition and the recursion to mimic going from 1 to 10.
I've completed the Graham's exercise Chapter 5.8,and my code is:
(defun max-min (vec &key (start 0) (end (length vec)))
(cond
((eql start (1- end)) (values (elt vec start) (elt vec (1- end))))
((zerop end) (values nil nil))
(t
(multiple-value-bind (x y) (max-min vec :start (1+ start) :end end)
(let* ((maxx x)(minn y))
(values (max maxx (elt vec start)) (min minn (elt vec start))))))))
You don't need to worry about the details, basically it just returns the max and min of a given vector in a "value" form.
I use the above recursion to solve the problem, but my teachers marked my function as "almost done" with such critique:
"If a function takes start and end, then length is neither needed nor correct. Length could be > 0 but it's whether start < end or not that matters. Testing end all by itself is not relevant at all."
I am not very clear at this point, I tried getting rid of the (length vec) default value for "end", but then the default value for end becomes nil.
We have clear instrution that "length" should at most be called once.
Could you please give me some hint on this? Thanks.
Your lambda list is OK. The problem is the base case: (zerop end) should be modified so that you also get a sensible result if called like (min-max myvec :start 5 :end 3).
The next critique is about these two lines:
(multiple-value-bind (x y) (max-min vec :start (1+ start) :end end)
(let* ((maxx x) (minn y))
;; ...
If you want the results of the recursive call to be named maxx and minn, why don't you name them like that directly?
(multiple-value-bind (maxx minn) (max-min vec :start (1+ start) :end end)
;; ...
By the way, you can call them max and min (there are separate namespaces for variables and functions), or max-of-rest and min-of-rest (to be more descriptive).
I don't know some of the lisp features you're using, but it looks to me very much like your teacher is incorrect.
"If a function takes start and end, then length is neither needed nor correct. Length could be 0 but it's whether start < end or not that matters. Testing end all by itself is not relevant at all."
It looks to me like length is the default value for end, and that you are only testing end, not testing length at all... His complaint already appears to be addressed.
That said, there are a other things to complain about in that code. For example, what happens if you call max-min with end < start? It looks to me like you'll recurse by incrementing start, until you run out of vector, then you'll get some kind of exception.