Common Lisp style question

186 views
Skip to first unread message

Edward Kenworthy

unread,
Jun 4, 2011, 3:07:23 AM6/4/11
to land-o...@googlegroups.com
Hi

Given:

(defstruct board num-columns num-rows squares)

Which is considered better Common Lisp style?

(defun draw-board (board)
  (let ((num-rows (board-num-rows board))
         (num-columns (board-num-columns board))
         (squares (board-squares board)))
    (loop for row below num-rows
        do (draw-row-pieces squares row num-rows num-columns)
             (draw-row-squares row num-rows num-columns))))

which avoids repeatedly looking up num-rows, num-columns and  squares (but which I worry is more imperative-style), or:

(defun draw-board (board)
    (loop for row below (board-num-rows board)
        do (draw-row-pieces (board-squares board) row (board-num-rows board) (board-num-columns board))
             (draw-row-squares row (board-num-rows board) (board-num-columns board))))

which avoids using a let, feels less imperative, and doesn't prematurely optimise the code and lets the compiler optimise (or at least assumes the compiler will do so) but is also more cluttered.

Any thoughts?

Edward


Purity Control

unread,
Jun 4, 2011, 4:47:36 AM6/4/11
to Land of Lisp
I can't comment on the best lisp style or which is more optimised -
there are more experienced lispers out there that will be able to shed
light on that.

As for styles I prefer the first one as it is clearer in intent (to me
anyway).
However it does look more imperative on the face of it but after much
thinking I'm not sure it is.

You are certainly creating variables that can be modified, but you
don't, you only use them as references. The fact that you could modify
the variable is a property of the struct. So although you don't you
could modify the struct in the second function also.

So I have an additional question.
What do you think makes the language more imperative. Is it the
assignment of variables or is it the use of mutable data structures.
eg. If the data structures were immutable in your example would you
worry about the lets?

Purity Control

unread,
Jun 4, 2011, 5:47:25 AM6/4/11
to Land of Lisp
Thinking about the compiler issue a little more.
While I don't know the answer as to which is more optimised. I
wouldn't let it affect my decision on going for the clearer code.
When you choose to develop in a higher level language you make the
implicit decision to trade an element of speed for faster, clearer
code that is easier to develop and maintain.
I think the only time to consider those questions would be if you were
hitting bottle necks in your code.

Peter Frings

unread,
Jun 4, 2011, 7:33:32 AM6/4/11
to land-o...@googlegroups.com, Purity Control, Edward Kenworthy
I prefer the first, with the (let).

As Craig said, it's clearer for the programmer and the ones that need to maintain it afterwards. Let the compiler figure out how to compile it in the most efficient way, and only optimize when it's indeed a verified bottleneck. In Knuth's words: "premature optimization is the root of all evil". (About optimization: often, using a better algorithm gains you more that tweaking a few bits here and there.)

So, go for the most understandable code.

As for the question whether it's too imperative, I would answer no. While the language allows you to modify those variables, you don't: you use them as constants. It's not because the language allows mutation, that your code is imperative. It's the code. (Which would've been my answer to the *ear-muffs* discussion a couple of days ago as well.)

A similar question is when using (nreverse) when returning a newly constructed list (common idiom in recursion with accumulators). It's not strictly functional, since you modify a variable. But for all practical purposes, it is functional (and it's also a bit of premature optimization :-) ).

So, adhere to the *ideas* of FP and avoid `extremism'. Else learn Haskell where even (random) is strict :-)

Cheers,
Peter.


Edward Kenworthy

unread,
Jun 4, 2011, 10:31:23 AM6/4/11
to land-o...@googlegroups.com
I was thinking the use of let to create local variables (as opposed to creating a closure) was what felt 'imperative'- immutability issues etc didn't concern me at all.

Creating the local variables felt 'right' to me as well- but then I have 30 years experience of developing in Algol-family languages so I can't necessarily trust my instincts when writing Lisp code!

Purity Control

unread,
Jun 4, 2011, 12:06:39 PM6/4/11
to Land of Lisp
I might not be understanding properly what you are trying to do, but
in this instance I think a closure would be a bad idea.
Then only thing you are binding to is the board struct.
A closure binds its variables when it is created.
The idea of draw-board is to show your current status.
A closure would end up showing the status of the board when you
created the closure.

Sequiturian

unread,
Nov 6, 2012, 1:45:06 PM11/6/12
to land-o...@googlegroups.com
Edward,

I prefer the second style; not because it's less imperative-style, but because I prefer not to have to go chasing down lexical variables all over the code in order to understand a function. For me, the fewer lexical variable used in lisp code, the better to see where all the intermediate results are coming from; hence, the easier to understand the code and see that is free of bugs.

LL

Munawar Cheema

unread,
Dec 30, 2012, 8:54:53 AM12/30/12
to land-o...@googlegroups.com
I like the second style for pretty much the same reasons.

Also, I believe the first is not "imperative style" and perfectly fine as I remember either Sussman or Abelson clearly stating in the SICP videos that the intial binding in a let is initialization and not the same as assigning to a variable already created.

Nicholas Patrick

unread,
Jan 2, 2013, 8:38:58 AM1/2/13
to land-o...@googlegroups.com
A solution that is somewhat in-between the two options could be to use with-slots...which may or may not be supported by your lisp implementation given that it's not in the spec for structures.  However, it is concise and achieves what you're looking for.
http://www.gigamonkeys.com/book/object-reorientation-classes.html

This discussion gives an explanation of some of the issues (portability) with using with-slots on a structure.
https://groups.google.com/forum/?fromgroups=#!msg/comp.lang.lisp/JYQZPkqrRo8/dTd1JDTbh_YJ
Reply all
Reply to author
Forward
0 new messages