Is it correct to use the backtick / comma idiom inside a (loop ...)? - lisp

I have some code which collects points (consed integers) from a loop which looks something like this:
(loop
for x from 1 to 100
for y from 100 downto 1
collect `(,x . ,y))
My question is, is it correct to use `(,x . ,y) in this situation?
Edit: This sample is not about generating a table of 100x100 items, the code here just illustrate the use of two loop variables and the consing of their values. I have edited the loop to make this clear. The actual loop I use depends on several other functions (and is part of one itself) so it made more sense to replace the calls with literal integers and to pull the loop out of the function.

It would be much 'better' to just do (cons x y).
But to answer the question, there is nothing wrong with doing that :) (except making it a tad slower).

I think the answer here is resource utilization (following from This post)
for example in clisp:
[1]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect (cons x y))
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.469 sec.
Run time: 0.468 sec.
Space: 1609084 Bytes
GC: 1, GC time: 0.015 sec.
NIL
[2]> (time
(progn
(loop
for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y)) ;`
()))
WARNING: LOOP: missing forms after DO: permitted by CLtL2, forbidden by ANSI
CL.
Real time: 0.969 sec.
Run time: 0.969 sec.
Space: 10409084 Bytes
GC: 15, GC time: 0.172 sec.
NIL
[3]>

dsm: there are a couple of odd things about your code here. Note that
(loop for x from 1 to 100000
for y from 1 to 100000 do
collect `(,x . ,y))
is equivalent to:
(loop for x from 1 to 100
collecting (cons x x))
which probably isn't quite what you intended. Note three things: First, the way you've written it, x and y have the same role. You probably meant to nest loops. Second, your do after the y is incorrect, as there is not lisp form following it. Thirdly, you're right that you could use the backtick approach here but it makes your code harder to read and not idiomatic for no gain, so best avoided.
Guessing at what you actually intended, you might do something like this (using loop):
(loop for x from 1 to 100 appending
(loop for y from 1 to 100 collecting (cons x y)))
If you don't like the loop macro (like Kyle), you can use another iteration construct like
(let ((list nil))
(dotimes (n 100) ;; 0 based count, you will have to add 1 to get 1 .. 100
(dotimes (m 100)
(push (cons n m) list)))
(nreverse list))
If you find yourself doing this sort of thing a lot, you should probably write a more general function for crossing lists, then pass it these lists of integers
If you really have a problem with iteration, not just loop, you can do this sort of thing recursively (but note, this isn't scheme, your implementation may not guaranteed TCO). The function "genint" shown by Kyle here is a variant of a common (but not standard) function iota. However, appending to the list is a bad idea. An equivalent implementation like this:
(defun iota (n &optional (start 0))
(let ((end (+ n start)))
(labels ((next (n)
(when (< n end)
(cons n (next (1+ n))))))
(next start))))
should be much more efficient, but still is not a tail call. Note I've set this up for the more usual 0-based, but given you an optional parameter to start at 1 or any other integer. Of course the above can be written something like:
(defun iota (n &optional (start 0))
(loop repeat n
for i from start collecting i))
Which has the advantage of not blowing the stack for large arguments. If your implementation supports tail call elimination, you can also avoid the recursion running out of place by doing something like this:
(defun iota (n &optional (start 0))
(labels ((next (i list)
(if (>= i (+ n start))
nil
(next (1+ i) (cons i list)))))
(next start nil)))
Hope that helps!

Why not just
(cons x y)
By the way, I tried to run your code in CLISP and it didn't work as expected. Since I'm not a big fan of the loop macro here's how you might accomplish the same thing recursively:
(defun genint (stop)
(if (= stop 1) '(1)
(append (genint (- stop 1)) (list stop))))
(defun genpairs (x y)
(let ((row (mapcar #'(lambda (y)
(cons x y))
(genint y))))
(if (= x 0) row
(append (genpairs (- x 1) y)
row))))
(genpairs 100 100)

Related

lisp: chunking a vector

As mentioned here, I'm trying to teach myself lisp by implementing lodash.
I have basically no experience with lisp, so work that would be trivial in js is foreign to me.
For instance, I'm working on implementation of a _.chunk method, which in js takes an array and a size variable and 'chunks' the array by the size:
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.chunk(['a', 'b', 'c', 'd'], 3);
// => [['a', 'b', 'c'], ['d']]
As somebody totally new to common lisp data types, I would assume that the analogous type would be a vector, not an array, is that correct?
Secondly, my way of solving this algorithmically would be to retain a length variable, and a pointer variable, and to grab a subset of the array/vector, [pointer to pointer + size], while pointer + size was < length, and then return [pointer to length] when that was no longer true, and incrementing pointer to pointer + size + 1 otherwise.
No idea how to implement this in lisp, here is my code so far.
(defun _.chunk (vector &optional (size 1 size-p))
(if (or (not size-p) (eq size 1))
vector
((let (
(array_length (array-total-size array))
(pointer)
)
???
))
)
)
For this implementation I would first write an idiomatic Common Lisp version of chunk that can be useful in a CL program (efficient, etc.), and then write a thin lodash layer that only wraps around those functions.
For example, I would first write a helper function to allow sharing storage with the chunked vector. A displaced array refers to another array but with an offset and different size. It may be useful to have chunks be only views of the original vector, so that they all share the same underlying storage array. It is not only a memory optimization: the behaviour is different when mutating either a chunk or the original vector, since any change in one is visible in the other. But as far as I know lodash is (was?) a pure functional language, so it makes sense to share some data if you don't mutate them. Some languages call those kind of indirect arrays "slices".
(defun slice (vector start end)
(make-array (- end start)
:element-type (array-element-type vector)
:displaced-to vector
:displaced-index-offset start))
So I would also make chunk-vector accept :start and :end parameters, as commonly done, along with sharedp which specifies if storage should be shared with the original vector:
(defun chunk-vector (size vector &key start end sharedp)
(check-type size (integer 1))
(loop
with slicer = (if sharedp #'slice #'subseq)
and low = (or start 0)
and high = (or end (length vector))
for s from low below high by size
for e from (+ low size) by size
collect (funcall slicer vector s (min e high))))
Note: I assume nil is a possible value for end that means the end of the vector, to mirror how subseq works. I do the same for start, because for those variables the nil value can be used without ambiguity to mean "default value". I could also have defined defaults in the lambda list, as done in tfb's answer.
Here are some tests:
(chunk-vector 3 #(0 1 2 3 4 5 6 7 8 9) :sharedp t)
(#(0 1 2) #(3 4 5) #(6 7 8) #(9))
(chunk-vector 2 #(0 1 2 3 4 5 6 7 8 9))
(#(0 1) #(2 3) #(4 5) #(6 7) #(8 9))
(chunk-vector 1 #(0 1 2 3 4 5 6 7 8 9))
(#(0) #(1) #(2) #(3) #(4) #(5) #(6) #(7) #(8) #(9))
Likewise, you could also define a chunk-list function and have the lodash chunck function dispatch to each specialized version based on the sequence type.
This can be done with CLOS, but since that is already demonstrated in another answer, I'll just define individual specialized functions.
Here is an implementation of chunk-list that is based on LDIFF.
I tried first mixing all cases in one function, but this becomes needlessly complex.
Here is first an unbounded chunk function:
(defun chunk-list/unbounded (size list)
(loop
for front = list then next
for next = (nthcdr size front)
collect (ldiff front next)
while next))
front is defined as initially list, then the current value of next at each step
next is the next chunk, computed using size; this plays nicely with lists that have not enough elements, since in that case nthcdr just returns the remaining elements.
A bit more complex case is required to handle the end argument, and for that we define the bounded version where there is also an additional upper-limit counter, that decreases by size at each step of iteration. It represents remaining number of elements to add, and is used along with size to compute (min size upper-limit), the size of the next chunk:
(defun chunk-list/bounded (size list upper-limit)
(loop
for front = list then next
for next = (nthcdr (min size upper-limit) front)
collect (ldiff front next)
do (decf upper-limit size)
while (and next (plusp upper-limit))))
Finally, chunk-list dispatches on both versions based on whether end is nil or not; the calls are inlined here (because we can):
(defun chunk-list (size list &key (start 0) end)
(declare (inline check-list/bounded check-list/simple))
(check-type size (integer 1))
(let ((list (nthcdr start list)))
(when list
(if end
(chunk-list/bounded size list (- end start))
(chunk-list/unbounded size list)))))
Some examples:
(chunk-list 3 '(1 2 3 4 5 6 7))
((1 2 3) (4 5 6) (7))
(chunk-list 29 '(1 2))
((1 2))
(chunk-list 2 (alexandria:iota 100 :start 0) :start 10 :end 20)
((10 11) (12 13) (14 15) (16 17) (18 19))
i would propose step-by step slicing iterating over the chunk index (since you can easily find out the total amount of chunks), using dotimes.
this could look something like the following:
(defun chunked (seq size)
(let* ((total (length seq))
(amount (ceiling total size))
(res (make-array amount :fill-pointer 0)))
(dotimes (i amount res)
(vector-push (subseq seq (* i size) (min (* (1+ i) size) total))
res))))
CL-USER> (chunked "abcdefgh" 3)
;; #("abc" "def" "gh")
CL-USER> (chunked #*00101 2)
;; #(#*00 #*10 #*1)
CL-USER> (chunked (list :a :b :c :d :e) 1)
;; #((:A) (:B) (:C) (:D) (:E))
CL-USER> (chunked (list :a :b :c :d :e) 4)
;; #((:A :B :C :D) (:E))
This is an addendum to coredump's answer, as well as referring to a comment by Kaz. Most of this is about style, which is always a matter of opinion and I do not claim my opinion is better than theirs: I just think it is interesting to talk about the choices as Lisp programming is very much about style choice, since the language is so flexible compared to most others. The last section ('extending') might be interesting however.
Argument order
The problem with a signature which is (size vector ...) is that size can't be optional. If you want it to be, it can't be the first argument to the function. Whether that outweighs the easy utility of partial-application libraries I don't know (however, in the 'do the right thing' spirit, if I wrote a partial application library it would allow you to specify which args it was currying, so this would not be a problem).
So if size needs to be optional then the argument order must be (vector size ...).
Further, since coredump's answer uses keyword arguments, I would make size be one as well as you almost never want to mix keyword & optional arguments. So that leads to a signature which would be (vector &key size start end sharedp), and I'd then write the actual function as
(defun chunk-vector (vector &key (size 1) (start 0) (end (length vector))
(sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
This slightly improves on coredump's version by defaulting the arguments in the arglist rather than later.
Extending chunk-vector
Pretty obviously you might want to chunk other kinds of things, such as lists, and pretty obviously the algorithm for chunking a list will be very different than that for chunking a vector, because you really do not want to repeatedly call subseq on a list.
Well, this is what CLOS is for. First of all we can define a generic chunk function:
(defgeneric chunk (thing &key)
;; in real life we might want to specify some of the keyword
;; arguments at the GF level, but we won't
)
And now define methods for classes we care about. Firstly the method to chunk vectors, which is pretty much the previous function:
(defmethod chunk ((thing vector) &key
(size 1) (start 0) (end (length thing)) (sharedp nil))
(check-type size (integer 1))
(let ((slicer (if sharedp #'slice #'subseq)))
(loop for s from start below end by size
for e from (+ start size) by size
collect (funcall slicer thing s (min e end)))))
And now, for instance, one to chunk lists. Note this may be buggy, and there may be better ways of doing this.
(defmethod chunk ((thing list) &key
(size 1) (start 0) (end nil endp) (sharedp nil))
;; This does not implemenent SHAREDP: this could only be useful for
;; the last chunk, and since you don't know if you could share a
;; chunk until you have already walked the list it did not seem
;; worth it. It may also be buggy in its handling of END.
(declare (ignorable sharedp))
(flet ((next (lt)
(nthcdr size lt))
(the-chunk (lt p)
(loop for c below (if endp (min size (- end p)) size)
for e in lt
do (print c)
collect e)))
(loop for tail on (nthcdr start thing) by #'next
for pos upfrom start by size
while (or (not endp) (< pos end))
collect (the-chunk tail pos))))
And of course you can now define methods on this function for other appropriate types.
The input could certainly be a vector (a vector is a 1-dimensional array). Lisp has a few more sensible options of how to represent the result: it could be a 2-dimensional array, a vector of vectors, or maybe even a list of vectors.
To get a 2-dimensional array:
(defun reshape-2d (column-count vector &optional padding-element)
(let* ((row-count (ceiling (length vector) column-count))
(array (make-array (list row-count column-count)
:initial-element padding-element)))
(loop :for i :below (length vector)
:do (setf (row-major-aref array i) (aref vector i)))
array))
To get a vector of vectors:
(defun chunkv (size vector)
(let ((vectors (make-array (ceiling (length vector) size))))
(loop :for i :below (length vector) :by size
:for j :below (length vectors)
:do (setf (aref vectors j) (subseq vector
i
(min (1- (length vector))
(+ i size)))))
vectors))
To get a list of vectors:
(defun chunkl (size vector)
(loop :for i :below (length vector) :by size
:collect (subseq vector
i
(min (1- (length vector))
(+ i size)))))
This last version could actually chunk any sequence because it only uses sequence functions.

Unused Lexical Variable

Just started learning lisp. I have no idea why I am getting these errors or even what they mean. I am simply trying to code an approximation of pi using the Gregory-Leibniz series, here is the code.
(defun gl (n)
(defparameter x 0) ;init variable to hold our runnning sum
(loop for y from 0 to n ;number of iterations, starting from 0 to desired n
(if (= y 0) ;if n is 0 then we just want 4
(defparameter w 4))
(if (> y 0) ;else, 4*(-1^y)/((2 * y)+1)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w)) ;add to our running sum
(write x)) ;once loop is over, print x.
I have tried using setq, defvar, let etc. instead of defparameter but I still get "Undeclared free variable X".
I also get the error "Unused lexical variable N" even though I am using it for my loop, which is weird also.
How can I fix this and why is it happening? Thanks!
Here is the code after Emacs auto-indented it:
(defun gl (n)
(defparameter x 0)
(loop for y from 0 to n
(if (= y 0)
(defparameter w 4))
(if (> y 0)
(defparameter w (* 4 (/ (exp -1 y) (+ (* 2 y) 1)))))
(+ x w))
(write x))
Compiling the following code with SBCL gives one error and two warnings.
One warning says that x is undefined.
You should not call defparameter from inside your function, since defvar and defparameter are used to declare dynamic variables and to set their value in the global scope. Prefer to have let bindings, or, since you already are using a loop, a with clause. When you want to modify a binding, use setf.
The errors comes from the macroexpansion of LOOP, which is malformed. For SBCL, that means that the code is treated as dead-code for the rest of the function compilation; that explains why n appears not to be used, which is what the second warning is about.
There are various fixes remaining to be done:
Use function EXPT, not EXP.
Calling (+ x w) only computes a value but does not modify x, the result is useless.
Prefer using if as expression, like a ternary operator in other languages, in your case the code can be simplified
Adding one can be done with function 1+ (that's the name of the function, not a special syntax for adding constants)
The write operation is rarely needed, especially if you are computing a mathematical formula; just return the value, and the REPL will print it automatically.
Small corrections that make your code works:
(defun gl (n)
(let ((x 0))
(loop
for y from 0 to n
for w = (if (= y 0)
4
(* 4 (/ (expt -1 y) (+ (* 2 y) 1))))
do (setf x (+ x w)))
(write x)))
I would personally get rid of x and w, and use a SUM loop clause.
(defun gl (n)
(loop
for y from 0 to n
sum (if (zerop y)
4
(* 4 (/ (expt -1 y)
(1+ (* 2 y)))))))

Sum numbers that are positive which is less than n

(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.

Position of All Matching Elements in List

I'm trying to write a function in Common Lisp similar to the built in position function, that returns a list of the positions of all elements in the haystack that match the needle, as opposed to just the first. I've come up with a few possible solutions (for example recursively searching for the next element using a cdr-from function on the position and adding the result to the previous position) but none of the approaches I've come up with so far seem particularly elegant.
Can anyone suggest what would be the best way of approaching this, as I'm currently struggling.
The obvious way to solve the problem is just to look at each element of the list in turn, and each time one compares as equal to the needle collect its position into an output list. Getting the position is very easy in this case, because we are starting from the beginning of haystack; we can use a variable to count the current position starting from 0.
So if we describe the full algorithm in a sentence, we'd say something like "to find all the positions of a needle in a haystack, for each element in the haystack, and the position starting from 0, when the element is equal to the needle, collect the position."
The LOOP facility is basically the right thing to break out when you want to do iterative processing. Even though its syntax is complicated to describe formally, after some experience you can pretty much just put the English-language description of the algorithm in the body of LOOP and it will work.
(defun all-positions (needle haystack)
(loop
for element in haystack
and position from 0
when (eql element needle)
collect position))
Take this one with a grain of salt (and be sure to load Alexandria beforehand):
(defun positions (item sequence &key (test #'eql))
(mapcar #'car
(remove item (map 'list #'cons (alexandria:iota (length sequence)) sequence)
:test-not test
:key #'cdr)))
That said, it does have the advantage of working on arbitrary sequences:
CL-USER> (positions 'x #(x x y y x x y y))
(0 1 4 5)
CL-USER> (positions 5 (list 5.0 -1 5 5.0 -1) :test #'=)
(0 2 3)
CL-USER> (positions #\l "Hello")
(2 3)
If you want a recursive function, rather than a (loop ...) based one, you could use something like:
(defun all-positions (needle haystack)
(labels ((f (n h c r)
(if (null h)
r
(if (eql (car h) n)
(f n (cdr h) (1+ c) (cons c r))
(f n (cdr h) (1+ c) r))))))
(reverse (f needle haystack 0 nil)))
Here's another (not necessarily better) way to do it.
(defun get-positions (needle haystack)
(let ((result nil))
(dotimes (i (length haystack))
(if (eq (nth i haystack) needle)
(push i result)))
(nreverse result)))

Scheme/Racket: do loop order of evaluation

The following procedure is valid in both scheme r6rs and Racket:
;; create a list of all the numbers from 1 to n
(define (make-nums n)
(do [(x n (- x 1)) (lst (list) (cons x lst))]
((= x 0)
lst)))
I've tested it for both r6rs and Racket and it does work properly, but I only know that for sure for DrRacket.
My question is if it is guaranteed that the step expressions ((- x 1) and (cons x lst) in this case) will be evaluated in order. If it's not guaranteed, then my procedure isn't very stable.
I didn't see anything specifying this in the standards for either language, but I'm asking here because when I tested it was evaulated in order.
They're generally not guaranteed to be evaluated in order, but the result will still be the same. This is because there are no side-effects here -- the loop doesn't change x or lst, it just rebinds them to new values, so the order in which the two step expressions are evaluated is irrelevant.
To see this, start with a cleaner-looking version of your code:
(define (make-nums n)
(do ([x n (- x 1)] [lst null (cons x lst)])
[(zero? x) lst]))
translate to a named-let:
(define (make-nums n)
(let loop ([x n] [lst null])
(if (zero? x)
lst
(loop (- x 1) (cons x lst)))))
and further translate that to a helper function (which is what a named-let really is):
(define (make-nums n)
(define (loop x lst)
(if (zero? x)
lst
(loop (- x 1) (cons x lst))))
(loop n null))
It should be clear now that the order of evaluating the two expressions in the recursive loop call doesn't make it do anything different.
Finally, note that in Racket evaluation is guaranteed to be left-to-right. This matters when there are side-effects -- Racket prefers a predictable behavior, whereas others object to it, claiming that this leads people to code that implicitly relies on this. A common small example that shows the difference is:
(list (read-line) (read-line))
which in Racket is guaranteed to return a list of the first line read, and then the second. Other implementations might return the two lines in a different order.