A number of the Common Lisp sequence functions take a proper sequence as an input and return a sequence as output. Starting with a proper sequence, how could the function not return another proper sequence? Example?
(mapcan #'rest (list (list 0 1 2) (cons :a :b)))
=> (1 2 . :b)
... but it is true that most of the time you can expect to have proper sequences as a result; functions might be underspecified for various reasons (cost to implementers, etc).
By the way, notice that NCONC is specified to return a list (at least in the HyperSpec), but the formal definition as given in the same page allows to have non-lists as a result, e.g. (nconc nil 2) is 2. This incomplete over-approximation of the type of result (in the signature, not the actual description of the function) contaminates all other results:
(mapcan #'rest (list (list) (cons 1 2)))
=> 2
See also Proposed ANSI Changes and ANSI Clarifications and Errata.
Related
I need to remove the last two elements from a list in common list, but I can remove only one. What's the way?
(defun my-butlast (list)
(loop for l on list
while (rest l)
collect (first l)))
Simple: reverse, pop, pop, reverse ;-) 1
More efficiently, the following works too:
(let ((list '(a b c d)))
(loop
for x in list
for y in (cddr list)
collect x))
This can also be written, for some arbitrary L and N:
(mapcar #'values L (nthcdr N L))
It works because iteration over multiple lists is bounded by the shortest one. What matters here is the length of the second list (we don't care about its values), which is the length of the original list minus N, which must be a non-negative integer. Notice that NTHCDR conveniently works with sizes greater than the length of the list given in argument.
With the second example, I use the VALUES function as a generalized identity function; MAPCAR only uses the primary value of the computed values, so this works as desired.
The behavior is consistent with the actual BUTLAST2 function, which returns nil for N larger than the number of elements in the list. The actual BUTLAST function can also deal with improper (dotted) lists, but the above version cannot.
1. (alexandria:compose #'nreverse #'cddr #'reverse)
2. BUTLAST is specified as being equivalent to (ldiff list (last list n)). I completely forgot about the existence of LDIFF !
There's a function in the standard for this: butlast, or if you're willing to modify the input list, nbutlast.
butlast returns a copy of list from which the last n conses have been omitted. If n is not supplied, its value is 1. If there are fewer than n conses in list, nil is returned and, in the case of nbutlast, list is not modified.
nbutlast is like butlast, but nbutlast may modify list. It changes the cdr of the cons n+1 from the end of the list to nil.
Examples:
CL-USER> (butlast '(1 2 3 4 5) 2)
(1 2 3)
CL-USER> (nbutlast (list 6 7 8 9 10) 2)
(6 7 8)
The fact that you called your function my-butlast suggests that you might know about this function, but you didn't mention wanting to not use this function, so I assume it's still fair game. Wrapping it up is easy:
CL-USER> (defun my-butlast (list)
(butlast list 2))
MY-BUTLAST
CL-USER> (my-butlast (list 1 2 3 4))
(1 2)
Is it possible to call make-array function with a list as parameter? For example:
(make-array '((length '("a" "b")) (length '("r" "8" "5"))))
return:
#<TYPE-ERROR expected-type: NUMBER datum: (LENGTH '(...
Even if I try to cast the result of length with the following command:
(coerce (length '(1)) 'number)
it works for one dimension array but not for two dimensions.
Is it possible to call make-array function with a list as parameter?
Yes, in fact you always have to pass it a list designator, but it has to be a list (or list designator) of integers. The list '((length '("a" "b")) (length '("r" "8" "5")))) has two lists as its elements, not integers. E.g., if you do (first '((length '("a" "b")) (length '("r" "8" "5"))))), you get (length '("a" "b")), not 2. You'd need to do (make-array (list (length …) (length …)) …) instead.
It's described pretty clearly in the documentation for make-array in the HyperSpec:
Function MAKE-ARRAY
Syntax:
make-array dimensions &key element-type initial-element initial-contents adjustable fill-pointer displaced-to
displaced-index-offset
=> new-array
Arguments and Values:
dimensions—a designator for a list of valid array dimensions.
E.g., (make-array '(2 2)) returns a 2 × 2 array. Or, if you need to dynamically compute the dimensions, just list them together. E.g., (make-array (list (length '(a b c)) (length '(d e)))) returns a 3 × 2 array.
Note that the argument is designator for a list. The glossary entry says:
list designator n. a designator for a list of objects; that is, an
object that denotes a list and that is one of: a non-nil atom
(denoting a singleton list whose element is that non-nil atom) or a
proper list (denoting itself).
That means that when you do (make-array 5), the 5 is actually acting as a designator for the list (5). You can really think of make-array always accepting a list as the first argument, but that in the case of a one-element list, you can just pass the single element instead, since it's unambiguous what you'd want.
Related
These are related, but not quite duplicates, since they are about how to create a list to pass to make-array, whereas this question is about whether a list can be passed to make-array.
How to make an array with size received as arguments in a function in LISP?
How to modify this "make-matrix" function?
Simple rule 1: if you quote it, it does not get evaluated.
This is data, not code: '((length '("a" "b")) (length '("r" "8" "5"))).
Why? Because it is quoted.
Simple rule 2: if you want to compute something, then write Lisp code, not literal data.
(list 1 2) -> (1 2)
(list (length '(a b c)) (length '(1 2 3 4))) -> (3 4)
Addressing an unanswered aspect of the subject of the question: much like Common Lisp lists, multidimensional arrays also have a literal representation, which can be convenient in some situations.
Lists
(list 'a 'b 'c)
;; is equivalent to
'(a b c)
A vector (single dimensional array) is represented as #[n](foo*) -- n,optional, being the number of elements and foo being the items in the vector, e.g.
(vector 1 2 3 4)
;; is equivalent to
#4(1 2 3 4)
;; or
#(1 2 3 4)
A 'proper' multidimensional array, i.e. an array larger than one dimension, is represented as: #nA<sequence> where n is the number of dimensions and <sequence> has a structure similar to a nested list, e.g.
(make-array '(2 3) :initial-contents '((a b c) (d e f)))
;; is equivalent to the following. Note, the 'inner most' array arrays must have the same number of objects, i.e. lisp won't auto-fill them with nil or anything else.
#2A((A B C) (D E F))
But you don't need to memorize that. Like many other forms, the Lisp reader accepts as input whatever it printed as output of make-array. (Given some caveats that I won't go into, or rather will leave as an exercise for the reader!)
(setf list (loop for i from 1 to 12 collect i))
(defun removef (item seq)
(setf seq (remove item seq)))
CL-USER> (removef 2 list)
(1 3 4 5 6 7 8 9 10 11 12)
CL-USER> (removef 3 list)
(1 2 4 5 6 7 8 9 10 11 12)
Why doesn't removef really modify the variable?
In Common Lisp, parameters are passed "by identity" (this term goes back to D. Rettig, one of the developers of the Allegro Common Lisp implementation). Think of pointers (to heap objects) being passed by values, which is true for most Lisp objects (like strings, vectors, and, of course, lists; things are slightly more complicated, since implementations might also have immediate values, but that's beside the point here).
The setf of seq modifies the (private, lexical) variable binding of the function. This change is not visible outside of removef.
In order for removef to be able to affect the surrounding environment at the point of the call, you need to make it a macro:
(defmacro removef (element place)
`(setf ,place (remove ,element ,place)))
You might want to take at look at setf and the concept of generalized references. Note, that the macro version of removef I provided above is not how it should actually be done! For details, read about get-setf-expansion and its ugly details.
If all you want to do is to destructively modify the list, consider using delete instead of remove, but be aware, that this might have unintended consequences:
(delete 2 '(1 2 3 4))
is not allowed by the ANSI standard (you are destructively modifying a literal object, i.e., part of your code). In this example, the mistake is easy to spot, but if you are 7 frames deep in some callstack, processing values whose origin is not entirely clear to you, this becomes a real problem. And anyway, even
(setf list (list 1 2 3 4))
(delete 1 list)
list
might be surprising at first, even though
(setf list (list 1 2 3 4))
(delete 2 list)
list
seems to "work". Essentially, the first example does not work as intended, as the function delete has the same problem as your original version of removef, namely, it cannot change the caller's notion of the list variable, so even for the destructive version, the right way to do it is:
(setf list (delete 1 (list 1 2 3 4)))
Here is an example of an implementation of removef that is "able to affect the surrounding environment at the point of the call", as stated by #Dirk.
(defmacro removef (item place &rest args &key from-end test test-not start end count key &environment env)
(declare (ignore from-end test test-not start end count key))
(multiple-value-bind (vars vals store-vars writer-form reader-form)
(get-setf-expansion place env)
(assert (length= store-vars 1) ()
"removef only supports single-value places")
(let ((v.args (make-gensym-list (length args)))
(store-var (first store-vars)))
(once-only (item)
`(let* (,#(mapcar #'(lambda (var val)
`(,var ,val))
vars vals)
,#(mapcar #'(lambda (v.arg arg)
`(,v.arg ,arg))
v.args args)
(,store-var (remove ,item ,reader-form ,#v.args)))
,writer-form)))))
The utilities length= , make-gensym-list and once-only are available at Project Alexandria.
BTW exists at Alexandria a removef definition that uses define-modify-macro but requires an auxiliary definition. This version does not requires an auxiliary defintion.
In Common Lisp, is there a function in the standard library that simply returns the parameter given (i.e. doesn't manipulate the data)? This function would be equivalent to (lambda (x) x). I'm looking to use it as the default for an optional parameter. For example, such a function would replace (lambda (x) x) in:
(defun some-function (value &optional (transformation (lambda (x) x)))
(other-function (funcall transformation value))
Take a look at identity:
Function IDENTITY
Syntax:
identity object ⇒ object
Arguments and Values:
object—an object.
Description:
Returns its argument object.
BTW, the ANSI CL standard specifies almost a thousand symbols.
You cannot learn them all overnight.
Also, Lisp is a language with a rich history, so if you want something "general purpose", chances are that either the language provides that, or some (semi-)standard library does.
Ask away! Do not reinvent the bike.
sds's answer describes the identity function, which meets the specification that you asked for: it's pretty much just (lambda (x) x). However, it is worth noting that in a function like
(defun some-function (value &optional (transformation (lambda (x) x)))
(other-function (funcall transformation value))
it might be more idiomatic to describe your transformation as a key, and to let nil indicate that no key function should be applied to the value. This behavior is present in many Common Lisp functions. For instance, member takes a key argument that is applied to each element of sequence to produce a value that's compared to the item being searched for:
CL-USER> (member nil '(1 2 3 4 nil 5 6 7 8))
(NIL 5 6 7 8)
CL-USER> (member nil '(1 2 3 4 nil 5 6 7 8) :key 'oddp)
(2 3 4 NIL 5 6 7 8)
The default behavior is the same as if you pass identity as the key:
CL-USER> (member nil '(1 2 3 4 nil 5 6 7 8))
(NIL 5 6 7 8)
CL-USER> (member nil '(1 2 3 4 nil 5 6 7 8) :key 'identity)
(NIL 5 6 7 8)
However, the default value isn't identity, but nil. The HyperSpec for member says about the key:
key—a designator for a function of one argument, or nil.
This is specified in 17.2.1 Satisfying a Two-Argument Test which states that:
If a :key argument is provided, it is a designator for a function of
one argument to be called with each Ei as an argument, and yielding an
object Zi to be used for comparison. (If there is no :key argument, Zi
is Ei.)
If you want to adopt this type of convention, then your code would be something like
(defun some-function (value &optional transformation)
(other-function (if (null transformation) value (funcall transformation value))))
In your case, this might not be a big difference, but it will avoid an extra function call. In general, this can be helpful because it makes it easier to pass key arguments to library functions without having to worry about whether they're nil or not.
To expand a bit on the question, #'identity would return its argument when you have a single argument. #'list would return multiple arguments as a list, and #'values would return them as multiple values, they serve the same purpose but have a very different API indeed.
If I understand correctly Clojure can return lists (as in other Lisps) but also vectors and sets.
What I don't really get is why there's not always a collection that is returned.
For example if I take the following code:
(loop [x 128]
(when (> x 1)
(println x)
(recur (/ x 2))))
It does print 128 64 32 16 8 4 2. But that's only because println is called and println has the side-effect (?) of printing something.
So I tried replacing it with this (removing the println):
(loop [x 128]
(when (> x 1)
x
(recur (/ x 2))))
And I was expecting to get some collecting (supposedly a list), like this:
(128 64 32 16 8 4 2)
but instead I'm getting nil.
I don't understand which determines what creates a collection and what doesn't and how you switch from one to the other. Also, seen that Clojure somehow encourages a "functional" way of programming, aren't you supposed to nearly always return collections?
Why are so many functions that apparently do not return any collection? And what would be an idiomatic way to make these return collections?
For example, how would I solve the above problem by first constructing a collection and then iterating (?) in an idiomatic way other the resulting list/vector?
First I don't know how to transform the loop so that it produces something else than nil and then I tried the following:
(reduce println '(1 2 3))
But it prints "1 2nil 3nil" instead of the "1 2 3nil" I was expecting.
I realize this is basic stuff but I'm just starting and I'm obviously missing basic stuff here.
(P.S.: retag appropriately, I don't know which terms I should use here)
A few other comments have pointed out that when doesn't really work like if - but I don't think that's really your question.
The loop and recur forms create an iteration - like a for loop in other languages. In this case, when you are printing, it is indeed just for the side effects. If you want to return a sequence, then you'll need to build one:
(loop [x 128
acc []]
(if (< x 1)
acc
(recur (/ x 2)
(cons x acc))))
=> (1 2 4 8 16 32 64 128)
In this case, I replaced the spot where you were calling printf with a recur and a form that adds x to the front of that accumulator. In the case that x is less than 1, the code returns the accumulator - and thus a sequence. If you want to add to the end of the vector instead of the front, change it to conj:
(loop [x 128
acc []]
(if (< x 1)
acc
(recur (/ x 2)
(conj acc x))))
=> [128 64 32 16 8 4 2 1]
You were getting nil because that was the result of your expression -- what the final println returned.
Does all this make sense?
reduce is not quite the same thing -- it is used to reduce a list by repeatedly applying a binary function (a function that takes 2 arguments) to either an initial value and the first element of a sequence, or the first two elements of the sequence for the first iteration, then subsequent iterations are passed the result of the previous iteration and the next value from the sequence. Some examples may help:
(reduce + [1 2 3 4])
10
This executes the following:
(+ 1 2) => 3
(+ 3 3) => 6
(+ 6 4) => 10
Reduce will result in whatever the final result is from the binary function being executed -- in this case we're reducing the numbers in the sequence into the sum of all the elements.
You can also supply an initial value:
(reduce + 5 [1 2 3 4])
15
Which executes the following:
(+ 5 1) => 6
(+ 6 2) => 8
(+ 8 3) => 11
(+ 11 4) => 15
HTH,
Kyle
The generalized abstraction over collection is called a sequence in Clojure and many data structure implement this abstraction so that you can use all sequence related operations on those data structure without thinking about which data structure is being passed to your function(s).
As far as the sample code is concerned - the loop, recur is for recursion - so basically any problem that you want to solve using recursion can be solved using it, classic example being factorial. Although you can create a vector/list using loop - by using the accumulator as a vector and keep appending items to it and in the exist condition of recursion returning the accumulated vector - but you can use reductions and take-while functions to do so as shown below. This will return a lazy sequence.
Ex:
(take-while #(> % 1) (reductions (fn [s _] (/ s 2)) 128 (range)))