I'm trying to write a function that recursively returns the negative values of a list. This is what I have so far:
(defun neg-nums (L)
(if (null L) nil
(let ((X (neg-nums (cdr L))))
(if (< (car L) 0) (append (list (car L)) X)))))
(print (neg-nums (list 1 -2 3 -4)))
I tried the let function outside of the recursion, and it works fine, so I know its something to do with trying to make it recursive. right now, it just outputs NIL when it should output (-2 -4).
(PS, the print function is so when I load it as a file, I can see the result right away.)
Any help would be appreciated.
Apologies, I just realized that I needed an extra X in the last line. the correct answer is this:
(defun neg-nums (L)
(if (null L) nil
(let ((X (neg-nums (cdr L))))
(if (< (car L) 0) (append (list (car L)) X) X))))
(print (neg-nums (list 1 -2 3 -4)))
Related
I have developed code to check through input to see if it is a palindrome or not but I am having difficulty figuring out how to print the output. I want the output to return "t" if the input is a palindrome and "nil" if not. Also a challenge that I wanted to give myself was to not use the reverse function so thats why my code is not as simple as it could be. Thanks in advance.
(defun palindromep(l)
(cond ((null l) nil (write nil))
(t (append (list (car l)) (palindromep (cdr l)) (list (car l) )))))
(palindromep '(a b b a))
(terpri)
(palindromep '(a b c b a))
(terpri)
(palindromep '(a b c))
(terpri)
(palindromep '(a (d e) (d e) a))
(terpri)
(palindromep '(a (d e) (e d) a))
Firstly, an empty list is a palindrome! If we reverse it, we get the same empty list.
Secondly, Lisp functions don't print their result values; they return these values.
In an interactive session, it is the listener which prints the resulting value(s) that emerge from the expression being evaluated. That expression itself doesn't have to print anything.
Therefore, we begin like this:
(defun palindromep (l)
(cond
((null l) t) ;; the empty list is a palindrome: yield true.
Note, by the way, that if we write this:
((null l) nil t) ;; the empty list is a palindrome: yield true.
that doesn't do anything. The extra nil expression is evaluated, producing nil, which is thrown away. The Lisp compiler will completely eliminate that.
What if the list is not a list at all, but an atom other than nil? Let's just go with that being a palindrome. A clarification of requirements is needed, though:
((atom l) t)
Now we know we are dealing with a non-empty list. If it has exactly one item, then it is a palindrome:
((null (cdr l)) t)
Now we know we are dealing with a list of two or more items. That is a palindrome if the first and last items are the same, and if the items in between them form a palindrome.
(t (let* ((first (car l))
(rest (cdr l))
(tail (last l))
(interior (ldiff rest tail)))
(and (eql first (car tail)) (palindromep interior))))))
The whole thing:
(defun palindromep (l)
(cond
((null l) t)
((atom l) t)
((null (cdr l)) t)
(t (let* ((first (car l))
(rest (cdr l))
(tail (last l))
(interior (ldiff rest tail)))
(and (eql first (car tail)) (palindromep interior))))))
Code golfing: in the cond construct described by ANSI CL, a clause is permitted to have just one form. If that forms yields a true value, then that value is returned. Thus we can remove the t's:
(defun palindromep (l)
(cond
((null l)) ;; t removed
((atom l)) ;; likewise
((null (cdr l))) ;; likewise
(t (let* ((first (car l))
(rest (cdr l))
(tail (last l))
(interior (ldiff rest tail)))
(and (eql first (car tail)) (palindromep interior))))))
Documentation about the functions ldiff and last can be found here.
Further golfing: if we have this pattern (cond (A) (B) ... (t Z)) we can just replace it by (or A B ... Z):
(defun palindromep (l)
(or (null l)
(atom l)
(let* ((first (car l))
(rest (cdr l))
(tail (last l))
(interior (ldiff rest tail)))
(and (eql first (car tail)) (palindromep interior)))))
cond is like a generalization of or that can specify an alternative result value for the each terminating true case.
To go on with code-golfing, since t or nil is expected, you can use only or and nil to express conditionals (and using short-circuitry of or and nil expressions).
Also it is good to be able to determine a :test keyword - since you want to control the crucial testing behavior.
To be able to use also inner lists, one could e.g. use equalp or even a custom comparison function.
(defun palindromep (l &key (test #'equalp))
(or (null l) (and (funcall test (car l) (car (last l)))
(palindromep (butlast (cdr l)) :test test))))
This evaluates
(palindromep '(a (d e) (d e) a))
as t but
(palindromep '(a (d e) (e d) a))
as nil.
Well, it is maybe a philosophical question, whether the latter should be t and the former nil.
To revert that behavior, we could write a custom testing function.
Like this:
(defun reverse* (l &optional (acc '()))
(cond ((null l) acc)
((atom (car l)) (reverse* (cdr l) (cons (car l) acc)))
(t (reverse* (cdr l) (cons (reverse* (car l) '()) acc)))))
(defun to-each-other-symmetric-p (a b)
(cond ((and (atom a) (atom b)) (equalp a b))
(t (equalp a (reverse* b)))))
Well, I use here some kind of a reverse*.
Then if one does:
(palindromep '(a (d e) (d e) a) :test #'to-each-other-symmetric-p) ;; NIL
;; and
(palindromep '(a (d e) (e d) a) :test #'to-each-other-symmetric-p) ;; T
Just to complete the other answers, I would like to point out that not using reverse will not only complicate your code enormously, but also make it far more inefficient. Just compare the above answers with the classic one:
(defun palindromep (l)
(equal l (reverse l)))
reverse is o(l), i.e. it takes time proportional to the length of the list l, and so does equal. So this function will run in o(l). You can't get faster than this.
So, I have this helper function that checks to see if there is a reflexive relationship between a list and a list of pairs.
(define helper
(lambda (L S)
(cond
((if (equal? L '()) #f ;; here, when L equals empty list, it should return #f, but somehow it returns #t even if L is '().
(if (equal? S (car (car L)))
(if (list-equal? (car L))#t
(helper (cdr L) S))
(helper (cdr L) S))))
)))
However, the part where it checks if L is an empty list returns true even if the list is an empty list, allowing my other function to return true.
I've been stumped trying to figure out why its returning #t instead of #f for hours. Please help me figure out what's making this happen.
Oh and I'm using Dr.Racket version 6.12.
EDIT: more clearly, I would like the function to return #f when L is '() as a base case so that the function doesn't need to do anymore recursion.
You put if forms within cond which is quite superfluous.
So your mistake was for sure your lack of understanding of the cond syntax.
Remember cond syntax goes like:
(cond (condition1 what-to-do-if-condition1-is-true)
(condition2 what-to-do-if-condition2-is-true)
( ... ... )
(else what-to-do-if-none-of-the-conditions-listed-above-evaluated-to-true))
So I formed your expression accordingly to:
(define helper
(lambda (L S)
(cond ((equal? L '()) #f)
((and (equal? S (car (car L))) (list-equal? (car L))) #t)
(else (helper (cdr L) S)))))
Since you didn't gave definition for list-equal? - I cannot run this code for testing.
You have nested if in cond. Lets rewrite you code som something identical:
(define helper
(lambda (L S)
(let ((result
(if (equal? L '())
#f
(if (equal? S (car (car L)))
(if (list-equal? (car L))
#t
(helper (cdr L) S))
(helper (cdr L) S)))))
(cond
(result result)
(else 'implementation-defined-value)))))
A cond will return a implementation defined value as the else clause should none of the previous predicates hit. Since your base casse returns #f it goes to the default else case.
Since the other answer show the code with cond, here is the same with if:
(define helper
(lambda (L S)
(if (equal? L '())
#f
(if (and (equal? S (car (car L)))
(list-equal? (car L)))
#t
(helper (cdr L) S)))))
You can also write this only with and and or:
(define helper
(lambda (L S)
(and (pair? L)
(or (and (equal? S (car (car L)))
(list-equal? (car L)))
(helper (cdr L) S)))))
I attempted a question of making a program that replaces all instances of an element A within a list L with T and unlike elements with NIL. The bet is to not use mapcar.
Here is what I did earlier. I am storing all T and NIL in a new list POS then returning POS.
(defun SRC (A L)
(defun _SRC (A L POS)
(COND ((NOT (EQUAL (CAR L) NIL))
(_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L))))))
((EQUAL (CAR L) NIL)
(APPEND POS (LIST (EQUAL A NIL))))
(T POS)))
(CDR (_SRC A L (LIST NIL))))
Current behaviour:
The program is working nicely, except when searching for NIL itself, but that special case is not of concern here.
Few example runs of my code:-
(SRC 'g '(a g g o t g))
> (nil t t nil nil t)
When searching for NIL in a list:-
(SRC nil '(t a t nil nil))
> (nil nil nil t)
In this singular case our program ends on finding the first NIL in the list, for other searches, the program works fine. So I tried adding the ability of searching within lists of lists.
My updated code for searching within lists of lists without mapcar:
(defun SRC (A L)
(defun _SRC (A L POS)
(COND ((LISTP (CAR L))
(APPEND POS (LIST (SRC A (CAR L)))))
((NOT (EQUAL (CAR L) NIL))
(_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L))))))
((EQUAL (CAR L) NIL)
(APPEND POS (LIST (EQUAL A NIL))))
(T POS)))
(CDR (_SRC A L (LIST NIL))))
Now, the output that I expect from this code is as follows:
(SRC 'e '(a b e c (e g e) h t e))
> (nil nil t nil (t nil t) nil nil t)
Instead my code runs forever, causing stack overflow, and I could not figure out anything with callstacks or backtracking.
Unreadable code due to lack of indentation.
Your code is unreadable, because your code is not indented.
(defun SRC (A L)
(defun _SRC (A L POS)
(COND ((NOT (EQUAL (CAR L) NIL)) (_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L))))))
((EQUAL (CAR L) NIL) (APPEND POS (LIST (EQUAL A NIL))))
(T POS)))
(CDR (_SRC A L (LIST NIL))))
Let's indent your code.
(defun SRC (A L)
(defun _SRC (A L POS)
(COND ((NOT (EQUAL (CAR L) NIL))
(_SRC A (CDR L) (APPEND POS (LIST (EQUAL A (CAR L))))))
((EQUAL (CAR L) NIL)
(APPEND POS (LIST (EQUAL A NIL))))
(T POS)))
(CDR (_SRC A L (LIST NIL))))
Style and basic mistakes
Basic mistakes or programming style problems:
defun should not be nested. defun is not for defining local functions. defun should only be used for global functions. Use flet or labels for local functions.
use first and rest instead of car and cdr
use speaking variables
use lowercase
Don't start with nested functions
I would start without nested functions.
(defun _src (element list pos)
(cond ((not (equal (first list) nil))
(_src a (rest list) (append pos (list (equal element (car list))))))
((equal (first list) nil)
(append pos (list (equal element nil))))
(t pos)))
(defun src (element list)
(cdr (_src element list (list nil))))
Simplify recursion
But then you can greatly simplify it using the usual recursive pattern:
(defun mark% (element list result)
(if (null list)
result ; empty list -> return result
(mark% element ; mark the rest of the list
(rest list)
(cons (equal element (first list)) ; equal for the first element?
result))))
(defun mark (element list)
"return a list with boolean values if element is found in the list"
(reverse (mark% element list nil))) : needs to reverse the result
Note
Generally don't program recursive functions like that, since Lisp actually already offers MAP and MAPCAR - those provide the mapping functionality in one place and it is not needed to bake the recursive mapping into each function of your own.
Preferably use higher level iteration facilities like LOOP:
CL-USER 13 > (loop for e in '(a b a b)
collect (equal 'a e))
(T NIL T NIL)
Nested lists
You can adapt the above function to nested lists by adding a case testing for the first element being a list and then doing something in that case...
(defun mark% (element list result)
(cond ((null list)
result)
((consp (first list))
(mark% element
(rest list)
(cons (mark element (first list))
result)))
(t
(mark% element
(rest list)
(cons (equal element (first list))
result)))))
Debugging
Use trace and/or step to see what your code is doing.
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.
I have tried many times but I still stuck in this problem, here is my input:
(define *graph*
'((a . 2) (b . 2) (c . 1) (e . 1) (f . 1)))
and I want the output to be like this: ((2 a b) (1 c e f))
Here is my code:
(define group-by-degree
(lambda (out-degree)
(if (null? (car (cdr out-degree)))
'done
(if (equal? (cdr (car out-degree)) (cdr (car (cdr out-degree))))
(list (cdr (car out-degree)) (append (car (car out-degree))))
(group-by-degree (cdr out-degree))))))
Can you please show me what I have done wrong cos the output of my code is (2 a). Then I think the idea of my code is correct.
Please help!!!
A very nice and elegant way to solve this problem, would be to use hash tables to keep track of the pairs found in the list. In this way we only need a single pass over the input list:
(define (group-by-degree lst)
(hash->list
(foldl (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst)))
The result will appear in a different order than the one shown in the question, but nevertheless it's correct:
(group-by-degree *graph*)
=> '((1 f e c) (2 b a))
If the order in the output list is a problem try this instead, it's less efficient than the previous answer, but the output will be identical to the one in the question:
(define (group-by-degree lst)
(reverse
(hash->list
(foldr (lambda (key ht)
(hash-update
ht
(cdr key)
(lambda (x) (cons (car key) x))
'()))
'#hash()
lst))))
(group-by-degree *graph*)
=> '((2 a b) (1 c e f))
I don't know why the lambda is necessary; you can directly define a function with (define (function arg1 arg2 ...) ...)
That aside, however, to put it briefly, the problen is that the cars and cdrs are messed up. I couldn't find a way to tweak your solution to work, but here is a working implementation:
; appends first element of pair into a sublist whose first element
; matches the second of the pair
(define (my-append new lst) ; new is a pair
(if (null? lst)
(list (list (cdr new) (car new)))
(if (equal? (car (car lst)) (cdr new))
(list (append (car lst) (list (car new))))
(append (list (car lst)) (my-append new (cdr lst)))
)
)
)
; parses through a list of pairs and appends them into the list
; according to my-append
(define (my-combine ind)
(if (null? ind)
'()
(my-append (car ind) (my-combine (cdr ind))))
)
; just a wrapper for my-combine, which evaluates the list backwards
; this sets the order right
(define (group-by-degree out-degree)
(my-combine (reverse out-degree)))