6 ms·
Sometimes Lisp can get annoying though. I've used libraries where a function might return 5-6 values and I only need the first and last. I need to bind all of
by adwf 11y ago
Sometimes Lisp can get annoying though. I've used libraries where a function might return 5-6 values and I only need the first and last. I need to bind all of them and then (declare (ignore...)) the useless bits otherwise I get compiler warnings.
It's an annoyance, because I always feel the general ethos of Lisp is to eliminate tedious typing and multiple value returns frequently add a lot of cruft.
- junke 11y agoI agree that Lisp is not always terse, which surprised me at first too. You can abstract many constructs and eradicate redundancy, but at some point, your only chance of being terser is to use reader macros. However, doing so might not be a good idea either. There are libraries out there that provide syntactic sugar for Common Lisp, which is often discarded because (i) they define their own "ghetto" dialect of Lisp (ii) it is in fact not very important to waste a character or two. Aesthetics alone is not a goal. For multiple values, you might still use a list instead, in which case you are back to the usual way of accessing data: (let ((list (multiple-value-list (get-decoded-time)))) (format t "Year: ~A~%Seconds: ~A" (sixth list) (first list))) If you only want to access a particular value, use "nth-value" (not possible in your example, of course).
- adwf 11y agoYeah, that's how I do it sometimes with other peoples code. But with my own code I much prefer using structs. Makes it much clearer to read and there is little implicit structure like with an ordered list. So my preferred way would look more like: (let ((struct (my-get-decoded-time))) (format t "Year: ~A~%Seconds: ~A" (time-year struct) (time-seconds struct))) With the original multiple value return, if there were a bug and I were reviewing the code, I'd need to also review get-decoded-time and see what order the values are in. If instead it returned structured data, I could skip that step as the values are clear. Lisp is still my favourite language. I generally rank languages by how much time/code I'm spending managing the language versus managing the problem I want to solve. Lisp is very good for that, very little cruft so it lets you focus directly on the problem at hand.
- junke 11y agoAgreed, structs and classes make often more sense to aggregate data, especially when they are all equally important.
- lispm 11y agoCommon Lisp is a programmable programming language. You need to hack around it. Don't like it? Improve it. Sketch: (defun make-vars (vars &aux syms) "creates uninterned symbols for vars named NIL. Returns a list with those replaced and a list of the new syms." (values (loop for var in vars if (eq var NIL) collect (let ((sym (gensym "ignore"))) (push sym syms) sym) else collect var) syms)) (defmacro multiple-value-bind-some (vars form &body body) "Similar to MULTIPLE-VALUE-BIND, but variables named NIL will be ignored." (multiple-value-bind (vars syms) (make-vars vars) `(multiple-value-bind ,vars ,form (declare (ignore ,@syms)) ,@body))) Example (defun foo (x) "returns five values" (values x (* x 2) (* x 3) (* x 4) (* x 5))) (defun test () (multiple-value-bind-some (a nil nil nil b) (foo 10) (list a b)))
- junke 11y agoI have a hunch that you defined make-vars as a separate function just to be able to nest two multiple-value-bind, one in the macro and one in the expanded form ;-)
- lispm 11y agoA replacement for MULTIPLE-VALUE-BIND, which uses MULTIPLE-VALUE-BIND itself, shows a bit of the value of MULTIPLE-VALUE-BIND.
- adwf 11y agoYeah, that's a great example of the power of Lisp! Of course it now also leads to one of Lisp's other problems; namely that after a while everyone ends up programming in their own private language of accumulated hacks :D
- lispm 11y agoThe user needs to learn more than in Java: 1) Learn to deal with a language which has an infinite number of syntactic abstractions. 2) Learn the typical patterns of syntactic abstractions (WITH- , BIND-, DEF- ...). 3) Learn how to write your own abstractions. Then groups will settle on common (!) Lisp patterns. See for example: https://common-lisp.net/project/alexandria/ https://common-lisp.net/project/alexandria/ There are lots of libraries which provide language extensions, which are used by many people. The extremes in Lisp are then: * no syntactic abstractions -> the power of Lisp wasted * using those syntactic abstractions which are approved by user groups, due to inclusion into libraries Above choices are relatively conservative. As another extreme, it is fully possible to change the language - but then Common Lisp provides more than macros to do so. See for example reader macros, CLOS MOP, customs evaluators/compilers, code walkers, ...