I have this function:
(defun test (variable)
(cond
((null variable) nil)
((< (- 12 (other-function variable) 3) 0) 1)
(t (- 12 (other-function variable) 3))
)
)
The idea is, if the result of the subtraction of 12 with the value of the function with 3 is less than 0, it returns 1. Else, it will just make the subtraction.
The "other-function" returns a number.
When i run this function, lispworks freezes. But if i run the function without the first condition:
(defun test (variable)
(cond
((null variable) nil)
(t (- 12 (other-function variable) 3))
)
)
it makes the subtraction without any problem.
Can someone help?
Thanks.
EDIT:
I tried this way with let:
(defun test (variable)
(let (x (other-function variable))
(cond
((null variable) nil)
((< (- 12 x 3) 0) 1)
(t (- 12 x 3)))
)
)
But i still got the same problem with lispworks wich is, it freezes. When i run without the following condition:
((< (- 12 x 3) 0) 1)
This function works correctly.
Unless you come up with your full code and a test case, this can't be reproduced.
CL-USER 1 > (lisp-implementation-type)
"LispWorks"
CL-USER 2 > (defun test (variable)
(cond
((null variable) nil)
((< (- 12 (other-function variable) 3) 0) 1)
(t (- 12 (other-function variable) 3))))
TEST
CL-USER 3 > (defun other-function (foo) (+ foo 1))
OTHER-FUNCTION
CL-USER 4 > (test 5)
3
CL-USER 5 > (test 500)
1
Also: LispWorks usually does not 'freeze' on an error.
Related
I am trying to understand Racket's macros. For that, I built this function for a specific purpose:
(define (while-less-fun max)
(cond [(< a (- max 1))
(and (begin (set! a (+ a 1)) (print "x") a) (while-less-fun max))]
[(< a max)
(begin (set! a (+ a 1)) (print "x") a)]
[(>= a max)
(begin (set! a (+ a 1)) (print "x") a)]
))
It works as intended on the REPL:
> a
2
> (while-less-fun 7)
"x""x""x""x""x"7
> a
7
I tried to transform the function above in the macro bellow. My goal would be to generate the same results:
(define-syntax while-less
(syntax-rules (do)
[(while-less maximo do begin-exp)
(cond [(< a (- maximo 1))
(and begin-exp (while-less maximo do begin-exp))]
[(< a maximo)
begin-exp]
[(>= a maximo)
begin-exp])]))
The expected result was:
(define a 2)
(while-less 7 do (begin (set! a (+ a 1)) (print "x") a))
(while-less 7 do (begin (set! a (+ a 1)) (print "x") a))
Evaluating the second line would print "x" 5 times and change a to be 7. Also, evaluating the third line would print "x" 1 time and would change a to be 8.
Unfortunately, this generates an infinite recursion which really surprises me.
What did I do wrong? Why did this infinite recursion happen?
I know that you should avoid writing macros when a function is able to solve the problem. But, is my approach the wrong way of trying to accomplish this task?
In the first cond clause, you call "(while-less maximo do begin-exp)" with the same arguments, the entire body of the macro will be expanded again by calling the same "(while-less maximo do begin-exp)", causing the loop.
What you can do is create a generic while for a condition:
(define-syntax while
(syntax-rules (do)
[(while condition do begin-exp)
(let loop ()
(when condition
begin-exp
(loop)))]))
> (define a 2)
> (while (< a 7) do (begin (set! a (+ a 1)) (print "x") a))
"x""x""x""x""x"
> (while (< a 7) do (begin (set! a (+ a 1)) (print "x") a))
>
So i have this macro (basically a for loop):
(defmacro for ((parameter start-value end-value &optional (step 1)) &body e)
(let ((func-name (gensym))
(end (gensym)))
`(labels ((,func-name (,parameter ,end)
(if (<= ,parameter ,end)
(progn ,#e
(,func-name (+ ,parameter ,step) ,end)))))
(,func-name ,start-value ,end-value))))
And i want to test it with this:
(print (let ((j 0) (k 1))
(for (i 1 10 (incf k)) (print i))))
What i get now is:
1, 3, 6, 10, NIL.
which means that my step increments after each iteration, but i want it to increment only once in the beginning for this output:
1, 3, 5, 7, 9, NIL.
What's wrong with my macro and what should i do?
You need to compute the step value outside the loop:
CL-USER 12 > (defmacro for ((parameter start-value end-value
&optional (step 1))
&body e)
(let ((func-name (gensym))
(step-name (gensym))
(end (gensym)))
`(labels ((,func-name (,parameter ,end ,step-name)
(when (<= ,parameter ,end)
,#e
(,func-name (+ ,parameter ,step-name)
,end
,step-name))))
(,func-name ,start-value ,end-value ,step))))
FOR
CL-USER 13 > (pprint (macroexpand-1 '(for (i 1 10 (incf k)) (print i))))
(LABELS ((#:G954 (I #:G956 #:G955)
(WHEN (<= I #:G956) (PRINT I) (#:G954 (+ I #:G955) #:G956 #:G955))))
(#:G954 1 10 (INCF K)))
CL-USER 14 > (let ((j 0) (k 1))
(for (i 1 10 (incf k))
(print i)))
1
3
5
7
9
NIL
If you don't want to pass the step-value all the time, you need an outer LET binding its value.
Note: some Lisp implementations (many interpreters and some compilers) don't support TCO (tail call optimisation).
I'm having trouble finding my error.
This keeps returning nil:
(even-greater-n 5 '(1 2 3 4 5 6 7))
(defun even-greater-n (n L)
(cond ((null L) nil)
((and (> (car L) n) (evenp n)) (car L))
(t (even-greater-n n (cdr L)))))
Your error
You are passing to evenp n
instead of (car L).
Iteration
This is relatively easy to implement using
loop:
(defun even-greater (n l)
(loop for k in l
when (and (< n k)
(evenp k))
return k))
(even-greater 5 '(1 2 3 4 5 6 7 8))
==> 6
Recursion
If you are required to use recursion, you can do it too:
(defun even-greater (n l)
(cond ((endp l) nil)
((and (< n (first l))
(evenp (first l)))
(first l))
(t (even-greater n (rest l)))))
(even-greater 3 '(1 2 3 4 5 6 7 8))
==> 4
Library
And, of course, Lisp has a very powerful library, including
find-if:
(defun even-greater (n l)
(find-if (lambda (k)
(and (< n k)
(evenp k)))
l))
(even-greater 2 '(1 2 3 4 5 6 7 8))
==> 4
You must look for (car L) is even or not.
Using find-if and a single, open-coded lambda function:
(defun even-greater (n list)
(find-if (lambda (item) (and (> item n) (evenp item))) list))
Using functional combinators:
;; Combine multiple functions with AND:
;; Returns a function of one-argument which
;; passes that argument to the functions in the list,
;; one by one. If any function returns nil, it stops
;; and returns nil. Otherwise it returns the value
;; returned by the last function:
(defun andf (&rest functions)
(lambda (arg)
(let (res)
(dolist (f functions res)
(unless (setf res (funcall f arg))
(return))))))
;; Returns a one-argument function which tests
;; whether its argument is greater than quant.
(defun greater (quant)
(lambda (arg) (> arg quant)))
;; "find it, if it is greater than n, and even"
(defun even-greater (n list)
(find-if (andf (greater n) #'evenp) list))
How would I recurse through nested lists?
For example, given: '((A 1 2) (B 3 4))
How would I add 2 to the second element in each nested sublist?
(defun get-p0 (points)
(loop for x from 0 to
(- (list-length points) 1) do
(+ 2 (cadr (nth x points)))
)
)
I'm not really sure why (get-p0 '((A 1 2) (B 3 4))) returns NIL.
I'd go with something like this:
(loop for (letter x y) in '((A 1 2) (B 3 4))
collect (list letter (+ 2 x) y))
The reason: it's shorter and you don't measure the length of the list in order to iterate over it (why would you do that?)
Since you ask for a recursive solution:
(defun get-p0 (lst &optional (n 0))
(if (null lst)
nil
(let ((elt1 (first lst)) (eltn (cdr lst)))
(if (listp elt1)
(cons (get-p0 elt1) (get-p0 eltn))
(cons (if (= n 1) (+ elt1 2) elt1) (get-p0 eltn (+ n 1)))))))
so
? (get-p0 '((A 1 2) (B 3 4)))
((A 3 2) (B 5 4))
and it recurses further down if necessary:
? (get-p0 '((A 0 2) ((B -4 4) (C 10 4))))
((A 2 2) ((B -2 4) (C 12 4)))
The way you put it, you can consider the problem as a basic recursion pattern: you go through a list using recursion or iteration (mapcar, reduce, etc.; dolist, loop, etc.) and apply a function to its entries. Here is a functional solution:
(defun get-p0 (points)
(mapcar #'add-2 points))
where the auxiliary function can be defined as follows:
(defun add-2 (lst)
"Add 2 to the 2nd item"
(let ((res '()))
(do ((l lst (cdr l))
(i 1 (1+ i)))
((null l) (nreverse res))
(push (if (= 2 i)
(+ 2 (car l))
(car l))
res))))
As written your 'loop' use does not return anything; thus NIL is returned. As is your code is simply iterating over x and computing something; that something isn't stored anywhere.
So, how to get your desired result? Assuming you are willing to modify each point in points, this should work:
(defun get-p0 (points)
(loop for x from 0 to (- (list-length points) 1) do
(let ((point (nth x points)))
(setf (cadr point) (+ 2 (cadr point)))))
points)
(defun merge-matrix (matrix-1 matrix-2)
(if (not (or (eql (matrix-rows matrix-1) (matrix-rows matrix-2)) (null matrix-1) (null matrix-2))) (error "Invalid dimensions."))
(cond
((null matrix-1) (copy-tree matrix-2))
((null matrix-2) (copy-tree matrix-1))
(t (let ((result (copy-tree matrix-1)))
(dotimes (i (matrix-rows matrix-1))
(setf (nth i result) (nconc (nth i result) (nth i matrix-2))))
result))))
(merge-matrix '((3 1) (1 3)) '((4 2) (1 1)))
*** - EVAL: variable NULL has no value
I receive an error like that how I can fix the problem, thanks
The OP's code works for me. However I felt motivated to improve it and
I implemented the same idea (but a bit more powerful).
The semantics are the same as Matlab's vertcat.
The function appends all arguments into one big matrix.
Note that due to the declarations my code should be super efficient.
(deftype mat ()
"Non-square matrices. Last index is columns, i.e. row-major order."
`(simple-array single-float 2))
(defun are-all-elements-typep (type ls)
(reduce #'(lambda (b x) (and b (typep x type)))
ls))
(defun are-all-matrix-heights-equalp (ls)
(let ((first-height (array-dimension (first ls) 0)))
(reduce #'(lambda (b x) (and b
(= first-height
(array-dimension x 0))))
ls)))
(defun vertcat (&rest rest)
(declare (type cons rest))
(unless (are-all-elements-typep 'mat rest)
(break "At least one of the arguments isn't a matrix."))
(unless (are-all-matrix-heights-equalp rest)
(break "All Matrices must have the same number of rows."))
(let* ((height (array-dimension (first rest) 0))
(widths (mapcar #'(lambda (mat) (array-dimension mat 1)) rest))
(result (make-array (list height
(reduce #'+ widths))
:element-type 'single-float))
(current-width 0))
(dotimes (m (length rest))
(let ((e (elt rest m)))
(destructuring-bind (y x) (array-dimensions e)
(dotimes (j y)
(dotimes (i x)
(setf (aref result j (+ current-width i))
(aref e j i))))
(incf current-width (elt widths m)))))
(the mat result)))
#+nil
(let ((a (make-array '(2 3)
:initial-contents '((1s0 2s0 3s0)
(2s0 4s0 5s0))
:element-type 'single-float))
(b (make-array '(2 2)
:initial-contents '((6s0 7s0)
(9s0 8s0))
:element-type 'single-float)))
(vertcat a b a))
;=> #2A ((1.0 2.0 3.0 6.0 7.0 1.0 2.0 3.0) (2.0 4.0 5.0 9.0 8.0 2.0 4.0 5.0))
The error message you're getting suggests that lisp is trying to treat one of your calls to null as a variable. I was able to replicate this behavior by defining matrix-rows like Frank Shearar did and deleting the parentheses around the ((null matrix-1) (copy-tree matrix-2)) s-expression, for example. I'd suggest you check your parentheses, either manually or using something like SLIME, which gave me a warning when I tried to compile the function.