Can you execute multiple statements in an "if" statement? - lisp

This is my function:
(defun MyFunction(input)
(let ((NEWNUM (find input num)))
(if (find input num) //if this
(setq num NEWNUM) (FUNCT2) //then execute both of these
(list 'not found)))) //else output this
So after the if statement I want to be able to execute (setq num NEWNUM) followed by (FUNCT2) in order to set a new variable and then call a function. Any ideas on how to do this?

To do several things in sequence, you want progn.
(defun MyFunction(input)
(let ((NEWNUM (find input num)))
(if (find input num) //if this
(progn
(setq num NEWNUM)
(FUNCT2)) //then execute both of these
(list 'not found)))) //else output this

When your if is 'one-armed', as they call it (that is, it contains no else branch), it's typically easier and more idiomatic to use when and unless: http://www.cs.cmu.edu/Groups/AI/html/hyperspec/HyperSpec/Body/mac_whencm_unless.html
When you call (when pred x y ... z), it will just evaluate x y z sequentially if pred is true. unless behaves similarly when pred is NIL. x y z can represent any number of statements from one upwards. Thus:
(when pred (thunk))
is just the same as
(if pred (thunk))
Some people say when and unless should always be used for 'one-armed-ifs' because of clarity.
Edit: Your thread gave me an idea. This macro:
(defmacro if/seq (cond then else)
`(if ,cond (progn ,#then) (progn ,#else)))
should enable this:
(if/seq (find input num) //if this
((setq num NEWNUM) (FUNCT2)) //then execute both of these
((list 'not found)))))
So the general format is:
(if/seq *condition* (x y ... z) (a b ... c))
Depending on the condition, it evaluates all of the subforms in the first or second, but only returns the last.

You can't use multiple statements with if, except with progn as posted above. But there is the cond form,
(cond
((find input num) // if this
(setq num NEWNUM) // then execute both of these
(FUNCT2))
(t
(list 'not found))) // else output this

Just to add, you could also use the (begin exp1 exp2...) syntax to evaluate more than one expression in Lisp sequentially. Using this on an if's branch will have the same effect as using multiple statements.

Related

how to return the value of a prime number while trying to print the sum of prime numbers in a range of numbers from check-prime to prime-sum

I was working on this question to print the sum of prime numbers in a range of numbers. The range values will be be taken as an input from the user. I got the syntax errors all cleared out but could not figure out how to return the value of the prime no. to the sum if it is true.
(defun check-prime(num)
(if (= num 1) nil)
;(setq i 2)
(loop for i from 2 to ( isqrt num) do
(if (= (mod num i) 0) nil t)
(= i (+ i 1))
)
)
(defun prime-sum(*begin* *end*)
(defvar *s* 0)
(defvar *i* *end*)
(loop for *i* from *end* to *begin* do
;i= 13
(if (check-prime *i*)
(= *s* (+ *s* *i* ) )
)
(= *i* (- *i* 1))
)
(write *s*)
)
(defun vals()
(print "enter the range1: ")
(defvar *begin* (read))
(print "enter the range2: ")
(defvar *end* (read))
(prime-sum *begin* *end*)
)
(print(vals))
;b =4
;e 13
Here is your function, cleaned up a bit and formatted in a conventional way:
(defun check-prime(num)
(if (= num 1) nil)
(loop
for i from 2 to (isqrt num)
do
(if (= (mod num i) 0) nil t)
(= i (+ i 1))))
There are multiple things that are incorrect, and they boil down to how are Lisp forms evaluated.
There is a special form progn in Common Lisp that is used to evaluate a list of expressions, with the following pattern:
(progn E1 E2 ... EN)
A lot of other functions in Lisp are described has having "an implicit progn", that's the case for defun which allows for more than one expression in its body, but since the progn doesn't appear literally it is implicit. The behavior is however always the same: each expression E1 to EN is evaluated in sequence, and evaluation of the whole progn are the values returned by the last expression, EN (that's where the N comes from in the name). In other words, the intermediate values from E1 etc. are discarded, the expressions are only useful for their side-effects.
In your code, that's the case for (if (= num 1) nil), which is an expression in the body of defun which is not the last one, and which doesn't even have side-effects. It is thus completely useless.
Likewise, in the loop macro, all that follows the do keyword are expressions that are evaluated for their side effects and do not contribute to the resulting value of the whole loop form.
In fact, loop is a bit complicated but here your don't have any accumulating clause in your loop (something like collect, append, sum etc. that would compute a result). Instead, your loop will always return nil.
Note also that for i from 2 to (isqrt num) takes care of incrementing i, you don't have to do it yourself like you tried in the do. Moreover, = is a comparison operator, in order to mutate i you would need to use setf instead: (setf i (+ i 1)), or (incf i) (which I repeat is unnecessary here).
To combine the first two expressions, I would write:
(if (= num 1) nil ...)
Where ... is the loop: because if is a functional if, it evaluates to whichever branch is selected by the condition.
And inside the loop, I would use never:
(loop for i from 2 to (isqrt num) never (= 0 (mod num i)))
The never clause makes the loop compute a boolean and halt as soon as the result is false.

a function called A-SUM that calculates Σpi=ni, where n≥0,p≥0. Below are examples of what A-SUM returns considering different arguments

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.

Using Lisp: define a function that takes a list and a number and returns true if the number occurs in the list

I am new to lisp and I have a problem, I'm trying to find the number in the list but it is not working. I haven't made the return statement yet
(defun num (x 'y)
(if (member x '(y)) 't nil))
(write (num 10 '(5 10 15 20)))
My output just outputs the nil instead of doing the function and I'm confused of what I am doing wrong.
Solution
(defun member-p (element list)
"Return T if the object is present in the list"
(not (null (member element list))))
The not/null pattern is equivalent to (if (member element list) t nil) but is more common.
In fact, you do not really need this separate function,
member is good enough.
The -p suffix stands for predicate, cf. integerp and upper-case-p.
Your code
You cannot quote lambda list elements, so you need to replace defun num (x 'y) with defun num (x y)
You need not quote t
Quoting '(y) makes no sense, replace it with y.
You do not need to write the function call, the REPL will do it for you.
See also
When to use ' (or quote) in Lisp?
Can you program without REPL on Lisp?
You are almost certainly expected to not just use member, but to write a function which does what you need (obviously in real life you would just use member because that's what it's for).
So. To know if an object is in a list:
if the list is empty it's not;
if the head of the list is equal to the object it is;
otherwise it is in the list if it's in the tail of the list.
And you turn this into a function very straightforwardly:
(defun num-in-list-p (n l)
;; is N in L: N is assumed to be a number, L a list of numbers
(cond ((null l)
nil)
((= n (first l))
t)
(t
(num-in-list-p n (rest l)))))
You could use the built in position function which will return the index of the number if it is in the list:
(position 1 '(5 4 3 2 1))
If you want to define your own function:
CL-USER> (defun our-member(obj lst)
(if(zerop (length lst))
nil
(if(equal(car lst)obj)
T
(our-member obj (cdr lst)))))
OUR-MEMBER
CL-USER> (our-member 1 '(5 4 3 2 1))
T
CL-USER> (our-member 99 '(1 2 3 4 5))
NIL
We can create a function called "our-member" that will take an object (in your case a number) and a list (in your case a list of numbers) as an argument. In this situation our "base-case" will be whether or not the length of the list is equal to zero. If it is and we still haven't found a match, we will return nil. Otherwise, we will check to see if the car of the list (the first element in the list) is equal to the obj that we passed. If so, we will return T (true). However, if it is not, we will call the function again passing the object and the cdr of the list (everything after the car of the list) to the function again, until there are no items left within the list. As you can see, The first example of a call to this function returns T, and the second example call returns NIL.
What makes this utility function a good example is that it essentially shows you the under workings of the member function as well and what is going on inside.

LISP : SYSTEM::READ-EVAL-PRINT: variable I has no value

I made a simple test function trying to assign j a value of i by calling (test j 10).
I am getting SYSTEM::READ-EVAL-PRINT: variable J has no value.
(DEFUN test (j i)
(LET ((j i))
(print j)
)
)
I'm unsure if you are aware that the variable j in the let and j defined in the parameters of test are two completely different variables. As a true refactoring would be to rename them so that it is clear, here is your code with that ambiguity removed:
(defun test (pj pi)
(let ((lj pi))
(print lj)))
This is exactly the same code since the new binding in the let effectively makes the old variable with that same name inaccessible for the duration of the let. The warning will be about pj since it is still unused in the function and thus you should consider removing it:
(defun test (pi)
(let ((lj pi))
(print lj)))
Usually having a parameter that is not used is a bug so CL nags about such things. However sometimes you make higher order functions that use functions you pass values. eg.
(defun map-assoc (fn lst)
(loop :for n :from 0
:for (k . v) :in lst
:collect (funcall fn k v n lst)))
Now imagine you want to make a list of just the keys.
(defun assoq-keys (lst)
(map-assoc (lambda (k v n lst)
(declare (ignore v n lst))
k)
lst))
(assoq-keys '((I . 1) (II . 2) (III . 3) (IV . 4) (V . 5)))
; ==> (I II III IV V)
The declare statement will supress the error that the other variables passed will not be used, but you must include them as that is the contract made by the map-assoc function. For a function that takes their values or perhaps swaps other there are other variables you will be using so passing the values is a good generalization.
I think you're misunderstanding how the arguments work. Your test function, in its current form, takes two arguments: j and i. You seem to only use i, so there's no reason to pass a second one. Consider
(defun test (i)
(let ((j i))
(print j)))
Then call it simply as (test 10).

function (OccurencesOfPrimes < list >) which counts the number of primes in a (possibly nested) list

I am working on problem to get the occurence of Prime in a list in lisp.
Input:
Write a function (OccurencesOfPrimes < list >) which counts the number of primes in a (possibly nested) list.
Output: Example: (OccurencesOfPrimes (((1)(2))(5)(3)((8)3)) returns 4.
I am using the below code but getting the error like:
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
)
)
LOOP: illegal syntax near (SETQ ISPRIME F) in
(LOOP FOR J FROM 2 TO I NEVER (ZEROP (MOD I J)) (SETQ ISPRIME F) (BREAK)
)
Any help.
It is important to keep the format consistent with the expected conventions of the language. It helps when reading the code (in particular with other programmers), and can help you see errors.
Also, you should use an editor which, at the minimum, keep tracks of parentheses. In Emacs, when you put the cursor in the first opening parenthesis, the matching parenthesis is highlighted. You can spot that you have one additional parenthesis that serves no purpose.
(
defun OccurencesOfPrimes (list)
(loop for i from 2 to 100
do ( setq isPrime t)
(loop for j from 2 to i
never (zerop (mod i j))
(setq isPrime f)
(break)
)
)
(if (setq isPrime t)
(append list i)
)
) ;; <- end of defun
) ;; <- closes nothing
In Lisp, parentheses are for the computer, whereas indentation is for humans. Tools can automatically indent the code according to the structure (the parenthesis), and any discrepancy between what indentation you expect and the one being computed is a hint that your code is badly formed. If you look at the indentation of your expressions, you can see how deep you are in the form, and that alone helps you understand the code.
Symbol names are dash-separated, not camlCased.
Your code, with remarks:
(defun occurences-of-primes (list)
;; You argument is likely to be a LIST, given its name and the way
;; you call APPEND below. But you never iterate over the list. This
;; is suspicious.
(loop
for i from 2 to 100
do
(setq is-prime t) ;; setting an undeclared variable
(loop
for j from 2 to i
never (zerop (mod i j))
;; the following two forms are not expected here according
;; to LOOP's grammar; setting IS-PRIME to F, but F is not
;; an existing variable. If you want to set to false, use
;; NIL instead.
(setq is-prime f)
;; BREAK enters the debugger, maybe you wanted to use
;; LOOP-FINISH instead, but the NEVER clause above should
;; already be enough to exit the loop as soon as its
;; sub-expression evaluates to NIL.
(break)))
;; The return value of (SETQ X V) is V, so here your test would
;; always succeed.
(if (setq is-prime t)
;; Append RETURNS a new list, without modifying its
;; arguments. In particular, LIST is not modified. Note that "I"
;; is unknown at this point, because the bindings effective
;; inside the LOOP are not visible in this scope. Besides, "I"
;; is a number, not a list.
(append list i)))
Original question
Write one function which counts all the occurrences of a prime number in a (possibly nested) list.
Even though the homework questions says "write one function", it does not say that you should write one big function that compute everything at once. You could write one such big function, but if you split your problem into sub-problems, you will end with different auxiliary functions, which:
are simpler to understand (they do one thing)
can be reused to build other functions
The sub-problems are, for example: how to determine if a number is a prime? how to iterate over a tree (a.k.a. a possibly nested list)? how to count
the occurrences?
The basic idea is to write an "is-prime" function, iterate over the tree and call "is-prime" on each element; if the element is prime and was never seen before, add 1 to a counter, local to your function.
You can also flatten the input tree, to obtain a list, then sort the resulting
list; you iterate over the list while keeping track of the last
value seen: if the value is the same as the previous one, you
already know if the number is prime; if the previous number differs, then
you have to test if the number is prime first.
You could also abstract things a little more, and define a higher-order tree-walker function, which calls a function on each leaf of the tree. And write another higher-order function which "memoizes" calls: it wraps around a
function F so that if you call F with the same arguments as before,
it returns the result that was stored instead of recomputing it.
Example
I'll combine the above ideas because if you give that answer to a teacher you are likely to have to carefully explain what each part does (and if you can, great for you); this is not necessarily the "best" answer, but it covers a lot of things.
(defun tree-walk-leaves (tree function)
(typecase tree
(null nil)
(cons
(tree-walk-leaves (car tree) function)
(tree-walk-leaves (cdr tree) function))
(t (funcall function tree))))
(defun flatten (tree &optional keep-order-p)
(let ((flat nil))
(tree-walk-leaves tree (lambda (leaf) (push leaf flat)))
(if keep-order-p
(nreverse flat)
flat)))
(defun prime-p (n)
(or (= n 2)
(and (> n 2)
(oddp n)
(loop
for d from 3 upto (isqrt n) by 2
never (zerop (mod n d))))))
(defun count-occurences-of-prime (tree)
(count-if #'prime-p (remove-duplicates (flatten tree))))
(count-occurences-of-prime '(((1)(2))(5)(3)((8)3)))
=> 4
If, instead, you don't want to remove duplicates but count the multiple times a prime number occurs, you can do:
(count-if (memoize #'prime-p) (flatten tree))
... where memoize is:
(defun memoize (function &key (test #'equalp) (key #'identity))
(let ((hash (make-hash-table :test test)))
(lambda (&rest args)
(let ((args (funcall key args)))
(multiple-value-bind (result exists-p) (gethash args hash)
(values-list
(if exists-p
result
(setf (gethash args hash)
(multiple-value-list (apply function args))))))))))
(memoize is useless if there are no duplicates)