From: Marcos Nunes
Subject: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <slrnf5k4q8.ds8.marcos.nunes76@localhost.localdomain>
OK, so as a first toy program, I thought I'd write a simple tic-tac-toe
game.
I didn't look at any functional language implementations of it, so I'd
have to force myself find my way through Lisp.

I have the board displayer, and the utility function, but somehow I feel
that the code is very messy. The utility function seems particularly
convoluted (or is it just that I'm not used to functional programming?)

How ugly is it? How can I improve it?

Thanks,
 -- mnunes

;; Tic-tac-toe game.
;;
;; The board is a 3x3 array, that should be initialized with zeroes.
;; Players will use "1" and "-1" on the board.
;;
(defun myprint-cell (c)
  "Prints a cell (X, O or '.', depending on its value
   (1, -1, 0)"
  (cond ((= c 1)
	 (princ "X "))
	((= c -1)
	 (princ "O "))
	(t
	 (princ ". "))))

(defun display-square (square)
  "Displays the game board."
  (loop for i from 0 to 2 do
	(loop for j from 0 to 2 do
	      (myprint-cell (aref square i j)))
	(format t "~%"))) ; This lone FORMAT looks strange, doesn't it?

(defun utility (square player)
  "Calculates the utility function for the board. Since each user has
   an identifying number (1 and -1), the result will be the number of
   the user who wins, or zero if nobody wins."
  (let ((indices '(((0 0) (0 1) (0 2)) ; Lines
		   ((1 0) (1 1) (1 2)) ;
		   ((2 0) (2 1) (2 2)) ;
		   ((0 0) (1 0) (2 0)) ; Rows
		   ((0 1) (1 1) (2 1)) ;
		   ((0 2) (1 2) (2 2)) ;
		   ((0 0) (1 1) (2 2)) ; Diagonals
		   ((0 2) (1 1) (2 0)))))
    (loop for index-seq in indices do
	  (when (apply #'= (mapcar (lambda (idx) (aref square (car idx) (cadr idx))) index-seq))
	    (return-from score (aref s (caar index-seq) (cadar index-seq))))) ; return value (either 1 or -1)
    (return-from utility 0))) ; return zero


(setf s (make-array  '(3 3) :initial-element 0)) ; This is the board.

(setf (aref s 0 0) 1)
(setf (aref s 1 1) 1)
(setf (aref s 1 2) 1)
(setf (aref s 0 2) -1)
(display-square s)
(format t "Score (should be zero): ~a ~%" (utility s nil))
(setf (aref s 2 2) 1)
(display-square s)
(format t "Score (should NOT be zero): ~a~%" (utility s nil))

From: Dan Bensen
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <f3d877$5un$1@wildfire.prairienet.org>
Marcos Nunes wrote:
> (format t "~%"))) ; This lone FORMAT looks strange, doesn't it?
Nah, it's not so bad.  There are other ways, though.
write-line and terpri do the same thing.
For a small fixed board like tic-tac-toe,
you can hard-code the three columns in one format form,
including the ~%, and there are other ways to print a longer
or arbitrary-length row.

> (when (apply #'= (mapcar (lambda (idx) (aref square (car idx) (cadr idx))) index-seq))
>   (return-from score (aref s (caar index-seq) (cadar index-seq))))) ; return value (either 1 or -1)
This looks like it also returns 0 on a completely empty row|col|diag.
I don't see it checking to make sure the values are nonzero.

-- 
Dan
www.prairienet.org/~dsb/
From: Ken Tilton
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <yiq6i.3357$Ka2.3268@newsfe12.lga>
Marcos Nunes wrote:
> OK, so as a first toy program, I thought I'd write a simple tic-tac-toe
> game.
> I didn't look at any functional language implementations of it, so I'd
> have to force myself find my way through Lisp.
> 
> I have the board displayer, and the utility function, but somehow I feel
> that the code is very messy. The utility function seems particularly
> convoluted (or is it just that I'm not used to functional programming?)
> 
> How ugly is it? How can I improve it?
> 
> Thanks,
>  -- mnunes
> 
> ;; Tic-tac-toe game.
> ;;
> ;; The board is a 3x3 array, that should be initialized with zeroes.
> ;; Players will use "1" and "-1" on the board.
> ;;
> (defun myprint-cell (c)
>   "Prints a cell (X, O or '.', depending on its value
>    (1, -1, 0)"
>   (cond ((= c 1)
> 	 (princ "X "))
> 	((= c -1)
> 	 (princ "O "))
> 	(t
> 	 (princ ". "))))
> 
> (defun display-square (square)
>   "Displays the game board."
>   (loop for i from 0 to 2 do
> 	(loop for j from 0 to 2 do
> 	      (myprint-cell (aref square i j)))
> 	(format t "~%"))) ; This lone FORMAT looks strange, doesn't it?

I would not worry about such stuff. But now that you have learned loop, 
you should look at format, seeif you can dump the whole thing in one go, 
without myprint-cell.

> 
> (defun utility (square player)
>   "Calculates the utility function for the board. Since each user has
>    an identifying number (1 and -1), the result will be the number of
>    the user who wins, or zero if nobody wins."
>   (let ((indices '(((0 0) (0 1) (0 2)) ; Lines
> 		   ((1 0) (1 1) (1 2)) ;
> 		   ((2 0) (2 1) (2 2)) ;
> 		   ((0 0) (1 0) (2 0)) ; Rows
> 		   ((0 1) (1 1) (2 1)) ;
> 		   ((0 2) (1 2) (2 2)) ;
> 		   ((0 0) (1 1) (2 2)) ; Diagonals
> 		   ((0 2) (1 1) (2 0)))))
>     (loop for index-seq in indices do
> 	  (when (apply #'= (mapcar (lambda (idx) (aref square (car idx) (cadr idx))) index-seq))
> 	    (return-from score (aref s (caar index-seq) (cadar index-seq))))) ; return value (either 1 or -1)

return-from score? where is that?

anyway, you could learn more loop, when and return and finally.

>     (return-from utility 0))) ; return zero

      nah, just say 0, lisp returns that. But when you jazz up the loop 
you will not need to.

kt

-- 
http://www.theoryyalgebra.com/

"Algebra is the metaphysics of arithmetic." - John Ray

"As long as algebra is taught in school,
there will be prayer in school." - Cokie Roberts

"Stand firm in your refusal to remain conscious during algebra."
    - Fran Lebowitz

"I'm an algebra liar. I figure two good lies make a positive."
    - Tim Allen
From: Luigi Panzeri
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <m2bqg54tvo.fsf@matley.muppetslab.org>
At first glance i think you can improve your code in several ways.

1) Why do you encode players with numbers. CL has symbols, so you can
use X and O for readibility, instead of 1 and -1.

2) You can use case instead of cond in the myprint-cell

3) You can use terpri to output a newline in display-square

4) remove unused args (player in utility?)

5) Use some and every to express the condition in your utility
function

6) Abstract in functions some compound forms you use with flet (or
with other defun)

Example (untested code):

(defun utility (square)
  (flet ((extract-cell-values (path) ; extract-cell-values along
					; straight 3-path
	   (mapcar (lambda (idx) (apply #'aref square idx)) path))

	 (win-condition-p (cell-values) ; check if tree cells values
					; are equal and not nil,
					; returning winning player
					; else nil
	   (let ((player (car cell-values)))
	     (when (every (lambda (value) (eq value player)) cell-values)
	       player))))
    
    (let* ((indices ...)
	   (cell-values (mapcar #'extract-cell-values indices))
	   (test (some #'win-condition-p cell-values)))
      (or test 0))))

-- 
Luigi Panzeri aka Matley

Why Lisp? http://alu.cliki.net/RtL%20Highlight%20Film
Quotes on Lisp: http://lispers.org/
From: Geoffrey Summerhayes
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <1180372715.083793.50130@h2g2000hsg.googlegroups.com>
On May 27, 7:25 pm, Marcos Nunes <··············@gmail.com> wrote:
> OK, so as a first toy program, I thought I'd write a simple tic-tac-toe
> game.
> I didn't look at any functional language implementations of it, so I'd
> have to force myself find my way through Lisp.
>
> I have the board displayer, and the utility function, but somehow I feel
> that the code is very messy. The utility function seems particularly
> convoluted (or is it just that I'm not used to functional programming?)
>

Banged together a list-of-lists alternate:

(defun make-board (size)
  (loop for x below size collect
        (loop for y below size collect #\.)))

(defun print-board (board &optional (stream *standard-output*))
  (format stream "~&~{~{+-~*~}+~:*~%|~{~A|~}~%~}~:*~{+-~*~}+~%"
board))

(defun utility (board)
  (labels ((exit-test (line)
             (when (and (char/= (first line) #\.)
                        (apply #'char= line))
               (return-from utility (first line))))
           (lines (board)
             (exit-test (loop for x from 0
                              for line in board
                              do (exit-test line)
                              collecting (nth x line)))))
    (lines board)
    (lines (apply #'mapcar (lambda (&rest rest)(reverse rest))
board))))

(defun nset-square (player x y board)
  (setf (nth x (nth y board)) player)
  board)

(defparameter *board* (make-board 3))

(print-board *board*)

+-+-+-+
|.|.|.|
+-+-+-+
|.|.|.|
+-+-+-+
|.|.|.|
+-+-+-+

(format *standard-output* "~&Utility:~A~%" (utility *board*))
Utility:NIL

(nset-square #\X 2 0 *board*)
(nset-square #\X 1 1 *board*)
(nset-square #\X 0 2 *board*)

(print-board *board*)

+-+-+-+
|.|.|X|
+-+-+-+
|.|X|.|
+-+-+-+
|X|.|.|
+-+-+-+

(format *standard-output* "~&Utility:~A~%" (utility *board*))
Utility:X

----
Geoff
From: John Thingstad
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <op.ts16k8c9pqzri1@pandora.upc.no>
On Mon, 28 May 2007 19:18:35 +0200, Geoffrey Summerhayes  
<·······@gmail.com> wrote:

Nice one!

>
> (defun print-board (board &optional (stream *standard-output*))
>   (format stream "~&~{~{+-~*~}+~:*~%|~{~A|~}~%~}~:*~{+-~*~}+~%"
> board))

For those too lazy to decrypt that format statement perhaps this will help.

"~& ; fresh-line

~{ ; iterate rows

    ; For each element in column print a +- finally a +
   ~{
      +-
      ~* ; go-to next
   ~}
   +

    ; Now reprocess the last column so we can read the values
    ~:* ; go-to back

    ~% ; terpri
    |
   ~{
     ~A| ; element followed by |
   ~}
   ~%

~}

; finally the last +- line
~:*
~{
    +-
    ~*
~}
+
~%" ;

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: John Thingstad
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <op.ts170jodpqzri1@pandora.upc.no>
On Mon, 28 May 2007 19:18:35 +0200, Geoffrey Summerhayes  
<·······@gmail.com> wrote:

>
> (defun utility (board)
>   (labels ((exit-test (line)
>              (when (and (char/= (first line) #\.)
>                         (apply #'char= line))
>                (return-from utility (first line))))
>            (lines (board)
>              (exit-test (loop for x from 0
>                               for line in board
>                               do (exit-test line)
>                               collecting (nth x line)))))
>     (lines board)
>     (lines (apply #'mapcar (lambda (&rest rest)(reverse rest))
> board))))
>

Why not replace
(lines (apply #'mapcar (lambda (&rest rest)(reverse rest)) board)

with the simpler
(lines (mapcar (lambda (col) (reverse col)) board)


-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
From: Geoffrey Summerhayes
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <1180406530.372763.180300@h2g2000hsg.googlegroups.com>
On May 28, 7:10 pm, "John Thingstad" <··············@chello.no> wrote:
> On Mon, 28 May 2007 19:18:35 +0200, Geoffrey Summerhayes  
>
> Why not replace
> (lines (apply #'mapcar (lambda (&rest rest)(reverse rest)) board)
>
> with the simpler
> (lines (mapcar (lambda (col) (reverse col)) board)

No, you missed it.

Test the transforms with '((1 2 3)(4 5 6)(7 8 9))

----
Geoff
From: Frank Buss
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <7d1e21ejvph4.g8u6nxq3w9i6$.dlg@40tude.net>
Marcos Nunes wrote:

> The utility function seems particularly
> convoluted (or is it just that I'm not used to functional programming?)

You don't need to use a functional style in Lisp. But as in every language,
your code should be easy to read and understand. If I have to think about
what (caar index-seq) (cadar index-seq) means, it is not easy to
understand.

(defun utility (square)
  (let ((indices '(((0 0) (0 1) (0 2)) ; Lines
		   ((1 0) (1 1) (1 2)) ;
		   ((2 0) (2 1) (2 2)) ;
		   ((0 0) (1 0) (2 0)) ; Rows
		   ((0 1) (1 1) (2 1)) ;
		   ((0 2) (1 2) (2 2)) ;
		   ((0 0) (1 1) (2 2)) ; Diagonals
		   ((0 2) (1 1) (2 0)))))
    (loop for line in indices do
          (let ((values (loop for (x y) in line
                              collect (aref square x y))))
            (let ((player (car values)))
              (when (apply '= values)
                (return-from utility player))))))
  0)

> (setf s (make-array  '(3 3) :initial-element 0)) ; This is the board.

You should not use setf at the top-level. Use defparameter instead.

Finally a version how I would write it, which works for bigger boards, too:

(defmacro aif (test then &optional else)
  `(let ((it ,test))
     (if it ,then ,else)))

#+:Lispworks (editor:setup-indent "aif" 2 2 4)

(defun display-square (square)
  (loop for i from 0 to 2 do
	(loop for j from 0 to 2 do
	      (aif (aref square i j)
                  (princ it)
                (princ #\.)))
        (terpri)))

(defun utility (square)
  (let ((size (car (array-dimensions square))))
    (flet ((test-line (x0 y0 dx dy)
             (let ((player (aref square x0 y0)))
               (loop for i from 0 below size
                     for x = x0 then (+ x dx)
                     for y = y0 then (+ y dy)
                     do (unless (eql player (aref square x y))
                          (setf player nil)
                          (loop-finish)))
               (when player
                 (return-from utility player)))))
      (loop for i from 0 below size do
            (test-line i 0 0 1)
            (test-line 0 1 1 0)
            (test-line 0 0 1 1)
            (test-line (1- size) 0 -1 1)))))

(defparameter s (make-array  '(3 3) :initial-element nil))
(setf (aref s 0 0) 'x (aref s 1 1) 'x (aref s 1 2) 'x (aref s 0 2) 'o)
(display-square s)
(format t "Score (should be nil): ~a ~%" (utility s))
(setf (aref s 2 2) 'x)
(display-square s)
(format t "Score (should NOT be nil): ~a~%" (utility s))

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Rainer Joswig
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <joswig-66BF04.14543528052007@news-europe.giganews.com>
In article <······························@40tude.net>,
 Frank Buss <··@frank-buss.de> wrote:

> Marcos Nunes wrote:
> 
> > The utility function seems particularly
> > convoluted (or is it just that I'm not used to functional programming?)
> 
> You don't need to use a functional style in Lisp. But as in every language,
> your code should be easy to read and understand. If I have to think about
> what (caar index-seq) (cadar index-seq) means, it is not easy to
> understand.
> 
> (defun utility (square)
>   (let ((indices '(((0 0) (0 1) (0 2)) ; Lines
> 		   ((1 0) (1 1) (1 2)) ;
> 		   ((2 0) (2 1) (2 2)) ;
> 		   ((0 0) (1 0) (2 0)) ; Rows
> 		   ((0 1) (1 1) (2 1)) ;
> 		   ((0 2) (1 2) (2 2)) ;
> 		   ((0 0) (1 1) (2 2)) ; Diagonals
> 		   ((0 2) (1 1) (2 0)))))
>     (loop for line in indices do
>           (let ((values (loop for (x y) in line
>                               collect (aref square x y))))
>             (let ((player (car values)))
>               (when (apply '= values)
>                 (return-from utility player))))))
>   0)

If you don't use any LOOP facilities you can use
DOLIST as well.

    (dolist (line indices)
      (let ((values (loop for (x y) in line
                          collect (aref square x y))))
        (let ((player (car values)))
          (when (apply '= values)
            (return-from utility player)))))

IF you use LOOP facilities then you can write:

    (loop for line in indices
          for values = (loop for (x y) in line
                             collect (aref square x y))
          for player = (car values)
          when (reduce #'= values)
          do (return-from utility player))

Avoid APPLY. If you want to reduce a sequence, use REDUCE.
REDUCE works on arbitrarily long sequences. APPLY does not.
Call functions and not symbols. #'= is usually better than '=.

> > (setf s (make-array  '(3 3) :initial-element 0)) ; This is the board.
> 
> You should not use setf at the top-level. Use defparameter instead.

For experimentation I use it all the time. If you
use DEFPARAMETER (and top-level variables) NEVER (!!!)
use variable names like s, i, x, and so on. DEFPARAMETER
declares a variable special and that would mean
that local (!!!) variables with those names will be
special, too! Convention is to use something like
*s*. 

> 
> Finally a version how I would write it, which works for bigger boards, too:
> 
> (defmacro aif (test then &optional else)
>   `(let ((it ,test))
>      (if it ,then ,else)))
> 
> #+:Lispworks (editor:setup-indent "aif" 2 2 4)

I wouldn't use those micro-optimizations. This is Paul-Graham-Style. ;-)

> 
> (defun display-square (square)
>   (loop for i from 0 to 2 do
> 	(loop for j from 0 to 2 do
> 	      (aif (aref square i j)
>                   (princ it)
>                 (princ #\.)))
>         (terpri)))

Interesting LOOP has an it-feature, which you can't use here...

This works:

(defun test1 ()
  (loop for i in '(1 2 3 4)
        when (and (evenp i) i)
        collect it))


This works not:

(defun test2 ()
  (loop for i in '(1 2 3 4)
        when (and (evenp i) i)
        collect (expt it 2)))


> (defun utility (square)
>   (let ((size (car (array-dimensions square))))
>     (flet ((test-line (x0 y0 dx dy)
>              (let ((player (aref square x0 y0)))
>                (loop for i from 0 below size
>                      for x = x0 then (+ x dx)
>                      for y = y0 then (+ y dy)
>                      do (unless (eql player (aref square x y))
>                           (setf player nil)
>                           (loop-finish)))
>                (when player
>                  (return-from utility player)))))
>       (loop for i from 0 below size do
>             (test-line i 0 0 1)
>             (test-line 0 1 1 0)
>             (test-line 0 0 1 1)
>             (test-line (1- size) 0 -1 1)))))
> 
> (defparameter s (make-array  '(3 3) :initial-element nil))

Again, never use a top-level special variable like that.

To give an illustration:

(defun foo ()
  (let ((s 3))
    (flet ((bar ()
             (format t "~%bar thinks s is ~a" s)))
      (function bar))))

Try something like:   (let ((s 10)) (let ((f (foo))) (funcall f)))

BAR thinks s 3, because it uses the lexical binding.


Now do

(defparameter s 20)

and redefine FOO to be the same, just recompile it...

(defun foo ()
  (let ((s 3))
    (flet ((bar ()
             (format t "~%bar thinks s is ~a" s)))
      (function bar))))

Now, try   (let ((s 10)) (let ((f (foo))) (funcall f)))

BAR now thinks s is 10. Not the global value, not the lexical
value, but the dynamic value from S.

Suddenly even the local s is no longer the lexical s, but
it uses dynamic binding! Common Lisp doesn't even
have a way to undefine that. You can't define
a variable to be a lexical variable.

This means a global special declaration can introduce
changes that are extremely hard to find and to debug.

The convention is
a) use names like *foo* for special variables
b) never use *foo* for lexical variables ;-)


> (setf (aref s 0 0) 'x (aref s 1 1) 'x (aref s 1 2) 'x (aref s 0 2) 'o)
> (display-square s)
> (format t "Score (should be nil): ~a ~%" (utility s))
> (setf (aref s 2 2) 'x)
> (display-square s)
> (format t "Score (should NOT be nil): ~a~%" (utility s))

-- 
http://lispm.dyndns.org
From: Frank Buss
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <1qlr6td6njpal$.1795wudpsatgu.dlg@40tude.net>
Rainer Joswig wrote:

> If you don't use any LOOP facilities you can use
> DOLIST as well.
> 
>     (dolist (line indices)
>       (let ((values (loop for (x y) in line
>                           collect (aref square x y))))
>         (let ((player (car values)))
>           (when (apply '= values)
>             (return-from utility player)))))

But there is still one LOOP facility in it :-)
I guess this could be solved with dolist and destructuring-bind (who has
invented this longish name for such a useful macro?).

> Call functions and not symbols. #'= is usually better than '=.

Why? Both is a valid function designator.

> Interesting LOOP has an it-feature, which you can't use here...
> 
> This works:
> 
> (defun test1 ()
>   (loop for i in '(1 2 3 4)
>         when (and (evenp i) i)
>         collect it))

Thanks, I forgot this nice LOOP feature.

-- 
Frank Buss, ··@frank-buss.de
http://www.frank-buss.de, http://www.it4-systems.de
From: Edi Weitz
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <ups4khp6v.fsf@agharta.de>
On Mon, 28 May 2007 18:28:42 +0200, Frank Buss <··@frank-buss.de> wrote:

>> Call functions and not symbols. #'= is usually better than '=.
>
> Why? Both is a valid function designator.

They mean different things.

  CL-USER 1 > (defun foo (x) (1+ x))
  FOO

  CL-USER 2 > (flet ((foo (x) (* x x)))
                (loop for i below 3
                      collect (list (funcall 'foo i)
                                    (funcall #'foo i))))
  ((1 0) (2 1) (3 4))

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Pascal Bourguignon
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <87ps4klrix.fsf@thalassa.lan.informatimago.com>
Edi Weitz <········@agharta.de> writes:

> On Mon, 28 May 2007 18:28:42 +0200, Frank Buss <··@frank-buss.de> wrote:
>
>>> Call functions and not symbols. #'= is usually better than '=.
>>
>> Why? Both is a valid function designator.
>
> They mean different things.
>
>   CL-USER 1 > (defun foo (x) (1+ x))
>   FOO
>
>   CL-USER 2 > (flet ((foo (x) (* x x)))
>                 (loop for i below 3
>                       collect (list (funcall 'foo i)
>                                     (funcall #'foo i))))
>   ((1 0) (2 1) (3 4))

Which means that if you want THE = operator, you should use THE symbol
CL:=, instead of (function =), since with (function =), the meaning
can be overridden either by a FLET/LABEL, or by a shadowed symbol in
the current pacakge.

(flet ((= (a b) (princ "Yow!")))
  (apply 'cl:= list-of-numbers))   ; does the right thing!



-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Lars Brinkhoff
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <85sl9g6tcb.fsf@junk.nocrew.org>
Pascal Bourguignon <···@informatimago.com> writes:
> you should use THE symbol CL:=, instead of (function =), since with
> (function =), the meaning can be overridden [...] by a FLET/LABEL

A conforming program is not allowed to override CL:=, as per CLHS
11.1.2.1.2.
From: Kent M Pitman
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <u3b1g9k7n.fsf@nhplace.com>
Lars Brinkhoff <·········@nocrew.org> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
> > you should use THE symbol CL:=, instead of (function =), since with
> > (function =), the meaning can be overridden [...] by a FLET/LABEL
> 
> A conforming program is not allowed to override CL:=, as per CLHS
> 11.1.2.1.2.

Indeed.

The "CL:" is a red herring, since this is not a package issue.
Pascal's claim would still be relevant (though I agree with Lars
that it is unfounded) even if just '= were use instead of 'cl:=.

But, moreover, I would appeal not just to CLHS but also to the
common sense of the Prisoner's Dilemma.

All symbols are either:
 1. Defined by someone else
 2. Defined by oneself

Working by cases...

1. Symbols that are defined by someone else should never be overridden by
FLET nor by global definition.  It's rude and it risks error.  If you
don't like someone else's symbol, shadow it.  If you import it, you
are saying you will respect it.  If you think you can import and then
redefine a symbol, you're asking to lose.  So whether CLHS said it or
not, I'd say that the more compelling rule is that since someone else
defined it, it should be left alone.

Those rules that are in that set of restrictions for CL are a pretty
good rule of thumb for all users of all packages to follow.  No, there
is not a strict requirement.  But let's just say it's a "style recommendation".

2. Symbols that you define yourself are not mysteries.  You own them.
You know what they do.  So if the issue is that you have a function
FOO that you wrote and you might FLET it also, then I've got to say
that's pretty weird at the outset unless it's part of some cooperative
protocol. Otherwise, you're asking to accidentally forget and do
  (defun foo () ...)
  (defmacro bar (...) `(foo ...))
  (flet ((foo ...))
    (bar ...))
thinking that you're safe, but forgetting the fact that you have a
global foo and that bar uses it.  So yes, if you do
  (flet ((foo ...))
    (funcall 'foo ...))
you might get the outer foo, but the (bar ...) will get the inner foo.
So, IMO, you shouldn't do it.  Basically, it's always presupposed that
you will manage your own affairs and keep this from happening, since 
you have "perfect knowlege" of your own code, and Lisp doesn't try to 
keep you from doing creative things...  But the easy way to avoid problems
is to just not FLET-bind something that is globally defined unless you are
specifically conspiring between the global and local functions to give a
meaning that is part of a coordinated abstraction... which doesn't come
up a lot, ut when it does is quite important to allow.

Once you use these rules the situation of 'foo being different than
#'foo, when both exists, doesn't really come up.  But what DOES come
up is that sometimes there is only a local definition.  And so #'foo
is the right thing.  In general, since in well-styled programs they
will never mean a different thing, I recommend always using #'foo so
you don't have to adjust it just because you have a flet of the definition.

The only place I'd use 'foo as a function is as shorthand for
 #'(lambda (&rest args) (apply #'foo args))
because if foo is later updated, this lambda expression will "pick up"
the new definition of FOO.  This is sometimes useful in mapping a function
that might get redefined during the mapping operation, or in setting the
syntax of a readmacro to something that you might want to redefine, etc.
Basically, things where you're telling some system facility the name of a
function that it will use repeatedly but that you want to retain some
control over.  But APPLY and FUNCALL are not such cases.
From: Larry Clapp
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <slrnf5rjgs.pe3.larry@theclapp.ddts.net>
On 2007-05-29, Kent M Pitman <······@nhplace.com> wrote:
> But, moreover, I would appeal not just to CLHS but also to the
> common sense of the Prisoner's Dilemma.
>
> All symbols are either:
>  1. Defined by someone else
>  2. Defined by oneself

As an expansion on Kent's case 2, consider:

CL-USER 7 > (defun foo () 'first)
FOO

CL-USER 8 > (setq f #'foo)
#<interpreted function FOO 217842DA>

CL-USER 9 > (funcall f)
FIRST

CL-USER 10 > (defun foo () 'second)
FOO

CL-USER 11 > (funcall f)
FIRST

CL-USER 12 > (defun foo () 'first)
FOO

CL-USER 13 > (foo)
FIRST

CL-USER 14 > (setq f 'foo)
FOO

CL-USER 15 > (funcall f)
FIRST

CL-USER 16 > (defun foo () 'second)
FOO

CL-USER 17 > (funcall f)
SECOND

In other words, if you want some later APPLY or FUNCALL to pick up the
new definition of a global function, use QUOTE (i.e. 'foo), otherwise
use FUNCTION (i.e. #'foo).

This can matter a lot if you redefine a function in one file that
you've APPLYed in another file.  When you load the new definition, you
probably want the APPLY to pick up the change.

-- Larry Clapp
From: Pascal Bourguignon
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <87646c0xqk.fsf@informatimago.com>
Lars Brinkhoff <·········@nocrew.org> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
>> you should use THE symbol CL:=, instead of (function =), since with
>> (function =), the meaning can be overridden [...] by a FLET/LABEL
>
> A conforming program is not allowed to override CL:=, as per CLHS
> 11.1.2.1.2.

Damn!  I always forget this section!...

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.
From: Lars Brinkhoff
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <85k5us6i7s.fsf@junk.nocrew.org>
Pascal Bourguignon wrote:
> Lars Brinkhoff wrote:
> > A conforming program is not allowed to override CL:=, as per CLHS
> > 11.1.2.1.2.
> Damn!  I always forget this section!...

Yes, it has its way of sneaking up on you.  Maybe you should print it
out and glue it to the side of your screen? :)
From: Rob Warnock
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <_qWdnVl02Msz5cbbnZ2dnUVZ_hqdnZ2d@speakeasy.net>
Rainer Joswig  <······@lisp.de> wrote:
+---------------
| If you use DEFPARAMETER (and top-level variables) NEVER (!!!)
| use variable names like s, i, x, and so on. DEFPARAMETER
| declares a variable special and that would mean
| that local (!!!) variables with those names will be
| special, too! Convention is to use something like *s*. 
+---------------

That's why I (nearly) always use my DEFLEX macro[1] for such
top-level manually-typed variables -- it uses DEFINE-SYMBOL-MACRO
to redirect to a (related) constructed *...* name so that the
top-level variable *can* be lexically re-bound:

    > (deflex foo 11)

    FOO
    > (defparameter *bar* 22)

    *BAR*
    > (defun top-vars () (list foo *bar*))

    TOP-VARS
    > (let ((foo 33)
	    (*bar* 44))
        (list* :local foo *bar* :global (top-vars)))

    (:LOCAL 33 44 :GLOBAL 11 44)
    > 

It prevents a lot of accidents while still allowing the
convenience of names like FOO, BAR, X, Y, Z, I, J, K, S, etc.

[Though you still have to avoid names like "T"!  ;-}  ]


-Rob

[1] See <·········································@speakeasy.net>
    (barely a month ago) for my latest version, along with a
    pointer to a required patch to CMUCL-19c or earlier for
    symbol-macro handling in MACROEXPAND-1.

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Thomas A. Russ
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <ymibqg3va4u.fsf@sevak.isi.edu>
Marcos Nunes <··············@gmail.com> writes:

> OK, so as a first toy program, I thought I'd write a simple tic-tac-toe
> game.
> I didn't look at any functional language implementations of it, so I'd
> have to force myself find my way through Lisp.
> 
> I have the board displayer, and the utility function, but somehow I feel
> that the code is very messy. The utility function seems particularly
> convoluted (or is it just that I'm not used to functional programming?)
> 
> How ugly is it? How can I improve it?
> 
> Thanks,
>  -- mnunes
> 
> ;; Tic-tac-toe game.
> ;;
> ;; The board is a 3x3 array, that should be initialized with zeroes.
> ;; Players will use "1" and "-1" on the board.

Why use 1, -1 and 0?  Why not use symbols like X, O and -?  ("." is a
bit hard to use without quoting, so I suggest using "-� instead.

> (defun myprint-cell (c)
>   "Prints a cell (X, O or '.', depending on its value
>    (1, -1, 0)"
>   (cond ((= c 1)
> 	 (princ "X "))
> 	((= c -1)
> 	 (princ "O "))
> 	(t
> 	 (princ ". "))))

This then becomes a much simpler function.  So much so that you probably
don't even need it:

(defun myprint-cell (c)
  (princ c)
  (princ " "))

The only other change to your routines below is to substitute #'eql (or
#'eq) for #'= in the comparison function.  OK, you'll also need to use a
binary form, like changing APPLY to REDUCE.

> (defun display-square (square)
>   "Displays the game board."
>   (loop for i from 0 to 2 do
> 	(loop for j from 0 to 2 do
> 	      (myprint-cell (aref square i j)))
> 	(format t "~%"))) ; This lone FORMAT looks strange, doesn't it?

You could use (terpri) instead of the format statement.

> (defun utility (square player)
>   "Calculates the utility function for the board. Since each user has
>    an identifying number (1 and -1), the result will be the number of
>    the user who wins, or zero if nobody wins."
>   (let ((indices '(((0 0) (0 1) (0 2)) ; Lines
> 		   ((1 0) (1 1) (1 2)) ;
> 		   ((2 0) (2 1) (2 2)) ;
> 		   ((0 0) (1 0) (2 0)) ; Rows
> 		   ((0 1) (1 1) (2 1)) ;
> 		   ((0 2) (1 2) (2 2)) ;
> 		   ((0 0) (1 1) (2 2)) ; Diagonals
> 		   ((0 2) (1 1) (2 0)))))
>     (loop for index-seq in indices do
> 	  (when (apply #'= (mapcar (lambda (idx) (aref square (car idx) (cadr idx))) index-seq))
> 	    (return-from score (aref s (caar index-seq) (cadar index-seq))))) ; return value (either 1 or -1)
                         ^^^^^ ??

>     (return-from utility 0))) ; return zero
> 
> 
> (setf s (make-array  '(3 3) :initial-element 0)) ; This is the board.
> 
> (setf (aref s 0 0) 1)
> (setf (aref s 1 1) 1)
> (setf (aref s 1 2) 1)
> (setf (aref s 0 2) -1)
> (display-square s)
> (format t "Score (should be zero): ~a ~%" (utility s nil))
> (setf (aref s 2 2) 1)
> (display-square s)
> (format t "Score (should NOT be zero): ~a~%" (utility s nil))
> 

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: John Thingstad
Subject: Re: Please check this bit of Lisp (how ugly is my code?)
Date: 
Message-ID: <op.ts3bz91zpqzri1@pandora.upc.no>
>
>
> Why don't you look for yourself :
> 10.6 CASE STUDY: A TIC-TAC-TOE PLAYER
> COMMON LISP:
> A Gentle Introduction to Symbolic Computation
> http://www.cs.cmu.edu/~dst/LispBook/index.html
>
> cheers
> bobi
>

This discussion has been done earlier this year.
You might want to look at my result at:

http//home.chello.no/~jthing
and choose Tic Tac Toe

-- 
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/