2

Does exist a function in LISP for making a sequence of integers like (0 1 2 3)?

I found make-sequence, but I didn't find out how to make a sequence of integers.

I tried make-list and nothing.

I know that in Scheme exists (build-list 5 (lambda (x) x)). I tried to change the build-list with make-list, but it didn't work.

Some ideas? Thanks

Edit: I need something like make-list 5 ==> (0 1 2 3 4)

3 Answers3

3

Simply done with loop:

(loop :for n :below 10 :collect n)        
; ==> (0 1 2 3 4 5 6 7 8 9)
Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • 4
    `(loop for n below 10 collect n)` – Kaz Dec 13 '16 at 22:27
  • I built my own function: `(defun build-sequence (length) (let ((seq '())) (dotimes (i length) (setq seq (cons i seq))) (reverse seq)))` – Valentin Emil Cudelcu Dec 13 '16 at 22:47
  • @Kaz I knew there were something like that but somehow I didn't remember :-) Updated. – Sylwester Dec 14 '16 at 09:11
  • @ValentinEmilCudelcu FYI, you implemented the well-known push/nreverse idiom (http://www.gigamonkeys.com/book/they-called-it-lisp-for-a-reason-list-processing.html) – coredump Dec 14 '16 at 10:01
  • @ValentinEmilCudelcu `(setq seq (cons i seq))` is what `(push i seq)` does. Moreover, `push` avoids evaluating `seq` twice. Usually we use `nreverse` to reverse a list that we just constructed ourselves, before returning it to the caller. `reverse` wastefully allocates a whole new list. – Kaz Dec 14 '16 at 15:44
  • There is no need to use keywords in `loop`; they only add keystrokes and noise. The designers of `loop` went out of the way to make it unnecessary to ever use package prefixes on the clause keywords by essentially treating them as strings: `:collect`, `cl-user:collect`, `mypackage:collect` are all equivalent. – Kaz Dec 14 '16 at 15:47
  • @Kaz It's a matter of opinion. How I see using keywords makes them different than the expressions, which might be symbols as well. I prefer readability before redundant keystrokes. Also without you get the symbols in the current package. – Sylwester Dec 14 '16 at 17:40
  • @Kaz How does `push` avoid evaluating `seq` twice? `(macroexpand '(push i seq)) ; ==> (setq seq (cons i seq))`. Seems to be its the exact same thing with fewer keypresses. – Sylwester Jan 08 '17 at 23:45
  • @Kaz @Sylwester I think that `(setq seq (cons i seq))` does NOT evaluate "seq" twice! It evaluates once "i" and once "seq", calls "cons" and puts the result into the cell-value of the symbol whose name is "seq". When you use `(setq seq (cons i seq))` instead of `(push i seq)`, the _reader_ (the "read" function) is called twice to resolve the "seq" string into the symbol whose name is "seq" (in the current package). – duthen Dec 07 '17 at 12:26
  • @duthen The expression contains two occurrences of `seq`; how can it not evaluate it twice? What if we replace `seq` with `(aref (cdr x) y)`? Do you believe that `(setq (aref (cdr x) y) (cons i (aref (cdr x) y)))` doesn't evaluate `x` and `y` and `(cdr x)` twice, and doesn' t index into the array twice? – Kaz Dec 07 '17 at 23:50
  • @duthen My point was that since `push` is a macro it gets expanded into `(setq seq (cons i seq))` before compilation. Thus its only a less typing matter and nothing to do with evaluation since the compiler will be compiling `(setq seq (cons i seq))` in both cases with the exact same result. – Sylwester Dec 08 '17 at 00:02
  • @Sylwester Expressions denoting places can contain subexpressions, and those have to be evaluated in order to access the place or store a value into it. An ANSI-CL-conforming `(push val place)` has to expand in such a way that if the evaluation of `place` produces side effects, those side effects happen only once. – Kaz Dec 08 '17 at 19:48
  • @Kaz True, but then instead of just `seq` you would have had a slightly more complex expression like `(push 1 (caddr x))` which would indeed turn into a `let*` chain to ensure only one evaluation. In the code above `seq` is a binding and thus it does not suffer from being evaluated more than once and the expansion reflects that. – Sylwester Dec 08 '17 at 22:22
  • @Kaz I'm sorry but the expression is `(setq seq (cons i seq))` but not `(setf seq (cons i seq))`, which is a little bit different. The expression you wrote `(setq (aref (cdr x) y) (cons i (aref (cdr x) y)))` will produce an error, because the first argument is not a variable. The trailing "q" in "setq" stands for "quote" and means that it does NOT evaluate its first argument. Hence "setq" is not like a normal function which evaluates all its arguments. – duthen Dec 18 '17 at 23:29
  • @duthen `(setq x y)` and `(setf x y)` are equivalent in Common Lisp if the `x` expression is a symbol. If it isn't a symbol, then the `setq` is erroneous. Hence, `setq` can always be replaced by `setf`, but not *vice versa*. Interestingly, under the `setq`, `x` may be a symbol macro which expands to a compound expression. E.g. `(symbol-macrolet ((x (slot-value obj 'slot))) (setq x 42))` will store 42 into `(slot-value obj 'slot)` even though `(setq (slot-value obj 'slot) 42)` is invalid. So though I made a mistake back there, you can in fact **indirectly** feed a compound place to `setq`. – Kaz Dec 19 '17 at 01:33
1

The Alexandria library, which is intended to work on any conforming implementation of Common Lisp, defines iota:

(iota 5)
=> (0 1 2 3 4)

You can also customize start and step:

(iota 3 :start 1 :step 1.0)   
=> (1.0 2.0 3.0)

But often you do not need to actually produce the list, you just want to iterate over the given range. That's why there is also map-iota:

(map-iota #'print 3 :start 1 :step 1.0) 
=> 3

In such cases you can of course use LOOP:

(loop for i from 1.0 below 22 by 1.5 do (print i))

Instead of do, you can also collect and obtain a list; this is a bit more verbose than iota, but easier to customize.

coredump
  • 37,664
  • 5
  • 43
  • 77
0

Lets see if can still write mac lisp of the top of my head:

(defun foo (num acc)
   (if (eq num 0)
        acc
       (foo (- num 1) (cons num acc))))

(foo 5 nil)  

should be

(1 2 3 4 5)
Ian A. Mason
  • 207
  • 3
  • 8
  • 1
    Don't use EQ for numbers, implementations are not required to guarantee that e.g. `(eq 3 (+ 2 1))`. See http://stackoverflow.com/questions/547436/whats-the-difference-between-eq-eql-equal-and-equalp-in-common-lisp – coredump Dec 13 '16 at 22:34
  • hey i was just enjoying being nostalgic. at least i didn't use rplacd – Ian A. Mason Dec 13 '16 at 22:37
  • 2
    I understand being nostalgic, but there are some factual errors in your answer I would rather not see being taught to beginners. – coredump Dec 13 '16 at 22:43
  • It works. Just edit it for the reason mentioned. As for beginners, this function foo points out the cleverness of building the list in reverse rather than starting with 1 and having to reverse a list on return, shows a recursive method. Using EQUAL instead of EQ would be nice. Putting in an optional so you could call (foo 5) inseatd of (foo 5 nil) would be nice. – kd4ttc Aug 25 '22 at 20:08