Counter variable in LISP - math

Define the function 'occ' that takes a list L and a symbol A and counts the occurance of symbol A in L.
Example:
(occ '(((s) o ) d) 'f) --> 0
What i have gotten so far:
(defun occ(list a)
(setq counter 0)
;Checks if the given list is has an nested list
(if (consp list)
; Breaking the list down atom by atom and recursing
(or (occ a (car list))
(occ a (cdr list)))
; checks if symbols are the same
(if(eq a list)
(setq counter(1+ counter)))))
However My output keep saying Nil instead of displaying the counter value.
I cannot use any higher-functions of LISP.

First of all, don't use setq for variable initialization inside yout function, use let. Second, let's look why you doing it wrong, your code:
(defun occ(list a)
(setq counter 0) ;; You always setting counter to 0 on new
;; level of recursion
(if (consp list)
(or (occ a (car list)) ;; You reversed arguments order?
(occ a (cdr list))) ;; according to your definition it must be
;; (occ (car list) a)
(if(eq a list)
(setq counter(1+ counter)))))
Anyway, you don't need any counter variables to do what you want.
Right function may look like this (i changed arguments order becaus it looks better for me to find SYMBOL in LIST):
(defun occ (sym nested-list)
(cond
((consp nested-list)
(+ (occ sym (car nested-list)) (occ sym (cdr nested-list))))
((eq sym nested-list) 1)
(t 0)))
CL-USER> (occ 'x '(((s) o ((f ()) f)) d))
0
CL-USER> (occ 'f '(((s) o ((f (x (((f))))) f)) d f))
4

If you feed your definition to SBCL:
; in: DEFUN OCC
; (SETQ COUNTER 0)
;
; caught WARNING:
; undefined variable: COUNTER
;
; compilation unit finished
; Undefined variable:
; COUNTER
; caught 1 WARNING condition
So you are modifying a global undefined variable counter. When do the function return? Well, or will return the very first non nil return from recursion with car or cdr. What returns values? Well when it's not a cons it will evaluate to the intermediate value of a incf of counter when the symbol matches or nil when it doesn't.
Try doing it like this:
(defun occ (list a &optional (counter 0))
(cond ((equal list a) (1+ counter))
((atom list) counter)
(t (occ (cdr list)
a
(occ (car list)
a
counter)))))
counter is an optional accumulator that you use to hold the values. Since it's passed it isn't shared between the recursive calls but replaced with the updated value at each call making it functional and easy to follow. When you need to search both car and cdr you recurse car with the counter of this stage and the returning value will be used as the counter in the cdr. For lists of atom this will be tail recursive if the implementation supports it. This supports finding symbols as tails of lists. eg. (occ '((x . x) . x) 'x) ; ==> 3 If you are sure you have no dotted list (every list is nil terminated) you can use the loop macro:
(defun occ (list a)
(loop :for e :in list
:counting (equal e a) :into count
:if (consp e)
:summing (occ e a) :into sum
:finally (return (+ count sum))))
;; tests
(occ '(x (x x (x (x ) x)) y z) 'y) ; ==> 1
(occ '(x (x x (x (x ) x)) y z) 'x) ; ==> 6
(occ '((x . x) . x) 'x) ; ERROR like "A proper list must not end with X".

Related

Lisp exit defun function with nil as value

I'm trying to do a recursive version of the function position called positionRec. The objective is define the position of an element in a list, and if the element is not in the list return "nil". For exemple:
(positionRec 'a '(b c d a e)) => 4
(positionRec 'a '(b c d e)) => nil
I have written:
(defun positionRec (c l)
(cond
((atom l) (return nil))
((equal c (first l)) 1)
(t (+ 1 (positionRec c (rest l)))) ) )
I don't succeed to return nil. I have an error "*** - return-from: no block named nil is currently visible"
Anyone can teach me how to do it?
Lisp is an expression language: it has only expressions an no statemends. This means that the value of a call to a function is simply the value of the last form involved in that call This is different than many languages which have both statements and expressions and where you have to explicitly litter your code with explicit returns to say what the value of a function call is.
A cond form in turn is an expression. The value of an expression like
(cond
(<test1> <test1-form1> ... <test1-formn>)
(<test2> <test1-form1> ... <test1-formn>)
...
(<testn> <testn-form1> ... <testn-formnn>))
is the <testm-formn> of the first <testm> which is true, or nil if none of them are (and as a special case, if there are no forms after a test which is true the value is the value of that test).
So in your code you just need to make sure that the last form in the test which succeeds is the value you want:
(defun positionRec (c l)
(cond
((atom l) nil)
((equal c (first l)) 1)
(t (+ 1 (positionRec c (rest l))))))
So, what use is return? Well, sometimes you really do want to say 'OK, in the middle of some complicated loop or something, and I'm done now':
(defun complicated-search (...)
(dolist (...)
(dolist (...)
(dotimes (...)
(when <found-the-interesting-thing>
(return-from complicated-search ...))))))
return itself is simply equivalent to (return-from nil ...) and various constructs wrap blocks named nil around their bodies. Two such, in fact, are dotimes and dolist, so if you want to escape from a big loop early you can do that:
(defun complicated-search (...)
(dolist (...)
(when ...
(return 3)))) ;same as (return-from nil 3)
But in general because Lisp is an expression language you need to use return / return-from much less often than you do in some other languages.
In your case, the modified function is going to fail: if you get to the ((atom l) nil) case, then it will return nil to its parent which will ... try to add 1 to that. A better approach is to keep count of where you are:
(defun position-of (c l)
(position-of-loop c l 1))
(defun position-of-loop (c l p)
(cond
((atom l) nil)
((equal c (first l)) p)
(t (position-of-loop c (rest l) (1+ p)))))
Note that this (as your original) uses 1-based indexing: zero-based would be more compatible with the rest of CL.
It would probably be idiomatic to make position-of-loop a local function:
(defun position-of (c l)
(labels ((position-of-loop (lt p)
(cond
((atom lt) nil)
((equal c (first lt)) p)
(t (position-of-loop (rest lt) (1+ p))))))
(position-of-loop l 1)))
And you could then use an iteration macro if you wanted to make it a bit more concise:
(defun position-of (c l)
(iterate position-of-loop ((lt l) (p 1))
(cond
((atom lt) nil)
((equal c (first lt)) p)
(t (position-of-loop (rest lt) (1+ p))))))
The main problem is that you're trying to deal with incommensurable values. On the one hand, you want to deak with numbers, on the other, you want to deal with the empty list. You cannot add a number to a list, but you will inherently try doing so (you have an unconditional (1+ ...) call in your default branch in your cond).
There are ways to work around that, one being to capture the value:
(cond
...
(t (let ((val (positionRec c (rest l))))
(when val ;; Here we "pun" on nil being both false and the "not found" value
(1+ val)))))
Another would be to use a method amenable to tail-recursion:
(defun positionrec (element list &optional (pos 1))
(cond ((null list) nil)
((eql element (head list)) pos)
(t (positionrec element (rest list) (1+ pos)))))
The second function can (with a sufficently smart compiler) be turned into, basically, a loop. The way it works is by passing the return value as an optional parameter.
You could build a version using return, but you would probably need to make use of labels for that to be straight-forward (if you return nil directly from the function, it still ends up in the (1+ ...), where you then have numerical incompatibility) so I would go with either "explicitly capture the value and do the comparison against nil/false" or "the version amenable to tail-call elimination" and simply pick the one you find the most readable.

Counting number of occurrences of elements in a list

I am writing a function called count-if, which takes in a predicate, p?, and a list, ls. The function returns the number of occurrences of elements in the nested list that satisfy p?
For example: (count-if (lambda (x) (eq? 'z x)) '((f x) z (((z x c v z) (y))))) will return 3. This is what I have written:
(define (count-if p ls) (cond
((null? ls) '())
((p (car ls))
(+ 1 (count-if p (cdr ls))))
(else
(count-if p (cdr ls)))))
But I just get an error. I could use some help finding a better way to go about this problem. Thanks!
What is the signature of count-if? It is:
[X] [X -> Boolean] [List-of X] -> Number
What does the first cond clause return? It returns:
'()
This is a simple type error. Just change the base case to 0 and count-if works.
Edit (for nested).
First we define the structure of the date as Nested.
A symbol is just fed into the score helper function. Otherwise the recursive call is applied on all nested sub-nesteds, and the results are summed up.
#lang racket
; Nested is one of:
; - Number
; - [List-of Nested]
; Nested -> Number
(define (count-if pred inp)
; Symbol -> Number
(define (score n) (if (pred n) 1 0))
; Nested -> Number
(define (count-if-h inp)
(if (symbol? inp)
(score inp)
(apply + (map count-if-h inp))))
(count-if-h inp))
(count-if (lambda (x) (eq? 'z x)) '((f x) z (((z x c v z) (y)))))
; => 3

I working through little lisper. The function lat? checks whether all elements of list are atoms or not

(defun lat
(lambda (l)
(cond ((null l) t)
((atom (car l))(lat (cdr l))
(t nil))))
The function takes a list as an argument. It is a recursive function that checks every element in the list. Whether it is atom or not. If every element is an atom, then it returns true else false.
Following is the error displayed
While compiling LAT :
Bad lambda list : (LAMBDA (L)
(COND ((NULL L) T) ((ATOM # #)) (T NIL)))
[Condition of type CCL::COMPILE-TIME-PROGRAM-ERROR]
Just like Hal Abelson called Scheme "lisp" in the SICP videos this book does the same, however the language in the book is a predecessor to Scheme and not Common Lisp. When you see:
(define name
(lambda (arg ...)
body ...)
This is the same as this in CL:
(defun name (arg ...)
body ...)
The reason is that in Scheme it's the same namespace for operator as well as operand bindings. A lisp-2 like Common Lisp can split it up like this:
(setf (fdefinition 'name)
(lambda (arg ...)
body ...))
This probably won't happen since you can always use defun, but in the event you return a function from a function you can do this or you must rely on funcall or apply to use the returned value:
;; This is a function that creates a function
(defun get-counter (from step)
(lambda ()
(let ((tmp from))
(incf from step)
tmp)))
When using this you might want to bind it globally:
(setf (fdefinition 'evens) (get-counter 0 2))
(evens) ; ==> 0
(evens) ; ==> 2
Or in functions you get it bound to normal variables and need to funcall or apply:
(defparameter *odds* (get-counter 1 2))
(funcall *odds*)
; ==> 1
Which one do you prefer?
(list (funcall *odds*) (evens))
; ==> (3 4)
The ? in lat? inidicated predicate and in CL a p in the end does the same. Your function latp is suppose to return nil or t so it should not return a function at all. Thus:
(defun latp (list)
(cond ((null list) t)
((atom (car list)) (latp (cdr list)))
(t nil)))
This of course is the same as:
(defun latp (list)
(or (null list)
(and (atom (car list))
(latp (cdr list)))))
Unlike Scheme using the name list as the argument does not affect the function call to list.

Occurrence of symbol A found anywhere in L. LISP

Here is my function
(defun freq (symbol_A List_L)
(cond ((atom (car List_L))
(cond ((eq (car List_L) symbol_A) t (+ 1 (freq symbol_A (cdr List_L))))
(t 0)))
(T (freq symbol_A (cdr List_L))))
)
I am getting an error variable ATOM has no value. Here is what I am testing with
(freq 'c '((a c) c e)) --> 2
(freq 'f '(((s) o ) d)) --> 0
(freq 'f '(((f) f) f f)) --> 4
Can not understand where is my error.
I also tried this:
(defun freq (a L)
(cond
((null L) 0)
((equal a (car L)) (+ 1 (freq a (cdr L))))
(t (freq a (cdr L)))))
Knowing that nil is an atom, you can simply recurse over the car and cdr of each cons cell. When you hit an atom, add 1 if it matches or 0 if it doesn't.
(defun freq (sym tree)
(if (atom tree)
(if (eq sym tree) 1 0)
(+ (freq sym (car tree)) (freq sym (cdr tree)))))
There is a syntax error in your code.
Indent and format your code
First you need to format your code:
(defun freq (A L)
(cond (atom (car L)) ; first clause
(eq A (car (car L ))) ; second clause
(T (+ 1 (freq A (cdr L)))) ; third clause
(T (freq A (cdr L))))) ; fourth clause
A useful COND:
(cond ((> i 0) :positive)
((< i 0) :negative)
(t :equal))
You have written something like:
(cond (> i 0) :positive
(< i 0) :negative
(t :equal))
Here a Lisp interpreter would complain that > has no value. It's because it is used as a variable. (> i 0) is seen as the first clause and the test form is the variable >. Since > usually is not a variable, this is an error.
A compiler might even reject the whole form at compile time, since there are clauses which are not lists.
As you can see the parentheses around a clause are missing in your code.
Check the syntax of cond...
cond {clause}* => result*
A cond has zero or more clauses.
clause::= (test-form form*)
Each clause is a list (!!) starting with a test-form and followed by zero or more forms.
It makes also no sense to have two clause with T as the test form. The first one will always be take and the second one will always be ignored.

how to expand a list outside a backquote - macrodefinition

I am trying to implement a macro which expands a unlimited list of triplet-arguments into lambda-function to check an argument (object).
e.g.
(where >= amount 5 equalp name "george")
=>
#'(lambda (arg)
(and
(>= (amount arg) 5)
(equalp (name arg) "george")))
I got quite close with this macrodefinition:
(defmacro where (&rest list-of-argument-triplets )
`#'(lambda (arg)
(and
,(do ( (counter 0 (+ counter 3)) (liste (list)))
( (>= counter (list-length list.of-argument-triplets)) liste)
(push `( ,(nth counter list-of-argument-triplets)
( ,(nth (+ counter 1) list-of-argument-triplets) arg)
,(nth (+ counter 2) list-of-argument-triplets)
liste)))))
but this expands to
#'(lambda (arg)
(and ((>= (amount arg) 5)
(equalp (name arg) "george"))))
which is one parentheses after the "and" too much. As a conclusion I would have to use an # in front of the result-form, but then the "#list" is treated
as if it is an parameter-name, and therefore I get an no-value error, instead of an expanded list.
*** - RETURN-FROM: variable #LISTE has no value
How can I fix that?
Code smell: you use NTH to access elements of a list.
I would first define a helper function, which makes out of the flat list a list of three element lists:
(defun triplets (list)
(loop while list
collect (list (pop list)
(pop list)
(pop list))))
CL-USER 1 > (triplets '(a b c d e f g h i))
((A B C) (D E F) (G H I))
The macro is then slightly simpler to write:
(defmacro where (&rest flat-triplets)
`#'(lambda (arg)
(and
,#(mapcar (lambda (triplet)
(destructuring-bind (fn accessor item)
triplet
`(,fn (,accessor arg) ,item)))
(triplets flat-triplets))))
CL-USER 2 > (macroexpand-1 '(where >= amount 5 equalp name "george"))
(FUNCTION (LAMBDA (ARG) (AND (>= (AMOUNT ARG) 5) (EQUALP (NAME ARG) "george"))))
T

Resources