Chapter 15- Dice of Doom. None of the methods are actually functional!

74 views
Skip to first unread message

Edward Kenworthy

unread,
May 24, 2011, 4:53:46 AM5/24/11
to Land of Lisp
Hi

Been reading your book with some ups and downs :) I learnt programming
back in the 80s by writing games on the Commodore Pet, so learning
Lips the same way seemed good. Then came the down- back then I could
write games that could (and did) compete with what was being sold
commercially, today there is no chance. Then the up was the web
server- nice!

But now a new and more serious 'down'.

Been working through C15, Dice of Doom, where you introduce the idea
of functions. The problem is that all but one of your so-called clean
functional methods isn't anything of the sort.

For example:

(defun board-array (lst)
(make-array *board-hexnum* :initial-contents lst))

Passing in the same parameters can result in different results if you
change the global variable *board-hexnum*. Oops!

(defun game-tree (board players spare-dice first-move)
(list player
board(add-passing-move board
player
spare-dice
first-move
(attacking-moves board player spare-
dice))))

Looks like it might be functional and clean -no calls to random and no
references to any globals but let's have a look at add-passing-move:

(defun add-passing-move (board player spare-dice first-move moves)
(if first-move
moves
(cons (list nil
(game-tree (add-new-dice board player (1- spare-
dice)) ; add reinforcement dice
(mod (1+ player) *num-players*) ; switch
players
0
t))
moves)))

Oh dear! Not only does it refer to a global, *num-players*, but it
calls another dirty method- add-new-dice. It cant be a clean function
if it calls dirty methods...

Basically only one function in this whole chapter (player-letter) is
actually functional, despite your labelling.

I think your chapter on functional programming is badly broken.

The way to fix this is to pass these values in as parameters rather
than using global parameters. Perhaps the board should also contain
its dimensions (although in your simple, square, board it would be
easy to calculate this by taking the square root of the number of
hexagons)?

Edward Kenworthy

unread,
May 24, 2011, 5:05:48 AM5/24/11
to Land of Lisp

Also, you could replace most occurrences (all except the one where you
create the array) of *board-hexnum* with (length board), where board
is passed in. Obviously where you repeatedly make this call, eg in a
loop, it would make sense to use a local variable.

R. Mark Volkmann

unread,
May 24, 2011, 8:52:31 AM5/24/11
to land-o...@googlegroups.com, Land of Lisp
I believe any variable name of the form *name* is understood to be a constant, so function isn't considered dirty because it uses them.

---
R. Mark Volkmann
Object Computing, Inc.

Conrad

unread,
May 24, 2011, 9:15:38 AM5/24/11
to Land of Lisp
Hi Edward;

You are of course right that these global, dynamic variables such as
*num-players* can be modified. It's a bit of a grey area as to whether
this means that functions that use these functions are no longer
"functional", since none of the code ever attempts to modify these
global variables- Here they are just used as constants. (of course
*board-hexnum* changes in value between versions of DOD, but this is
because these different versions are meant to be separate versions of
the program)

CL does have a defconstant command, and I agree it might be better to
define variables such as *num-players* with defconstant. However, in
my book I tried to avoid using obscure commands (the sheer number of
commands in CL overall is pretty overwhelming) and none of the CL
programmers I've worked with made use of defconstant in this scenario-
Writing a book is kind of a balancing act and I've made some trade
offs like this.

However Edward, I can't argue with your basic argument- You make a
valid point, though I'm OK with the decision I made in this case. I
can tell you though that you're the first person to ever raise this
argument :-)

Edward Kenworthy

unread,
May 24, 2011, 9:27:23 AM5/24/11
to land-o...@googlegroups.com

By that argument then if my method reads from a file but none of my code ever writes to it then that makes it functional? ;-)

> However Edward, I can't argue with your basic argument- You make a
> valid point, though I'm OK with the decision I made in this case.

I can certainly appreciate making such trade-offs 'in real life' but in a chapter about functional programming? 8)

> I can tell you though that you're the first person to ever raise this
> argument :-)


My dear old mother always told me I was special :)

Edward Kenworthy

unread,
May 30, 2011, 9:07:55 AM5/30/11
to land-o...@googlegroups.com

Hi

I was pretty sure your answer wasn't right but I wasn't sure exactly why.

I've had to do some further reading ("Let over Lambda" by Doug Hoyte, chapter 2) and now I know why it's completely wrong.

Bunny-ears (*name*) is a convention -and not everyone adheres to it anyway- for marking special variables (ie dynamically scoped ones- which is what you get from both defvar and defparameter) the convention does not mean that it is understood to be constant- in fact quite the opposite as it can be shadowed, which is a core 'feature' of dynamic scoping.

Consider this:

(defparameter *num-players* 2)

(defun foo()
*num-players*
)

What is the value of (foo) ?

If you said anything except 'it depends' then you were wrong.

Consider this pretty standard form in Lisp:

(let ((*num-players* = 3)
foo)

Now what value is returned by foo?

What about if foo has been memoized?

In that case you have no idea what value will be returned because you don't know what the value of *num-players* was at the time it was first called and therefore what value was cached!

This is why any method that uses a special variable or in any way uses such a method cannot be functional- you have no idea what it might return.

Edward

Edward Kenworthy

unread,
May 30, 2011, 9:11:26 AM5/30/11
to land-o...@googlegroups.com
PS

(defparameter *p* 1)
(constantp '*p*) evaluates to false, ie it's not a constant ;) 

Purity Control

unread,
May 30, 2011, 10:38:33 AM5/30/11
to Land of Lisp
I always stay out of these types of posts because they quite often
degenerate into flames, but cannot help myself this time because I can
see both view points and has made me question my views on what I
understand functional programming to be.

I think all the points that Edward raises are fair and technically
correct. However I am not sure how Conrad's answer is wrong when he
acknowledges this and explains that writing a book is about trade
offs.

I think really the issue here is about pragmatism.

- global variables can be modified and shadowed which technically
means this is bad from a functional point of view. However, Conrad
doesn't do these things so his functions are functional in the context
of the program.

Would you write this code if you were working in a team and hoped your
colleagues were disciplined enough to follow the same practices as
you? - probably not.
If you were the only one coding for fun or profit would you? Quite
possibly.

I have read many books on programming now and very few of them
actually get you excited enough to want to program and get you
programming real world interesting things quickly. Conrad's book does
but it already weighs in at 500 pages or so. As he said writing a book
is a balancing act. I am sure he could add more material to address
your concerns but I am not sure the book would flow the same. It
currently hits the balance between giving you the right amount of
boring theory before getting on with the fun stuff.

The book spends a little over 100 pages covering functional
programming. I doubt anyone is going to finish the book believing to
be an expert functional programmer. If it interests them they have
several books more reading to do before they will have a good solid
understanding of functional programming, and along the way they will
become more than aware of all the issues you raise.

I think also languages like Haskell force a functional programming
style but there is a reason why lisp is called the programmable
programming language. Lisp can be object orientated, procedural,
imperative and functional. You can bet it will be able to adapt to the
next craze that comes along, otherwise it wouldn't have had such an
impressive longevity. However this means that writing in a certain
style in lisp requires more discipline, because you don't have to.

I think that Conrad explains pretty succinctly what functional
programs need to do on page 293. At the end of the day we can use
language that enforce certain rules to make us behave in a certain way
or we can use something like lisp which allows us to do what we want.
However, the latter requires a greater understanding of what we are
doing and more discipline when we are programming. I think this is
what the cartoon on functional programming in the book tries to
highlight.

Edward Kenworthy

unread,
May 30, 2011, 1:41:07 PM5/30/11
to land-o...@googlegroups.com
Understand all of your points and in real life if one of my devs did this I'd at least listen to their argument before kicking their arse ;)

But in a book that's teaching functional programming?

I'd expect a much higher standard as the code is supposed to be an example of how to do it right. Sure there are compromises (the previous "comic" chapter makes that point) but in the DoD chapter the compromises should be isolated in the dirty functions- shouldn't they?

Beginners (including me with Lisp) need rules to follow- once you know the rules and when it's okay to break them you're no longer a beginner.

And it's not as if most of DoD couldn't have been written in a functional style- I've trivially re-written it so that almost all of the functions are clean and there are no special variables (if anyone is interested email me and I'll send you the code).

Cheers.

Purity Control

unread,
May 30, 2011, 5:04:56 PM5/30/11
to Land of Lisp
>Understand all of your points and in real life if one of my devs did this I'd at least listen to their argument before kicking their arse ;)

I like the way you think :-)

As I said I really can see both sides. I think you raise some valid
points and if I was coding this for myself I would probably be
practicing what you espouse.

I think our views are probably more in common than this thread would
suggest.

BUT

at the risk of sounding pedantic its not a book about functional
programming, its a book that is about learning lisp that covers both
imperative and functional styles showing that lisp can adapt to
different styles of programming.

Conrad uses the phrase "functional style" rather than "functional
program" and admits he is pushing the boundaries a little when he is
using loops etc. I think this gives him a little more license than you
are allowing him.

Beginners do need rules to follow and I understand that the changes
needed for a more functional program are pretty trivial.
But again this is where I think we differ a little. I would rather see
idiomatic lisp that I am more likely to come across as I look at other
peoples code, because that is what I want to learn from the book. Once
I get that then I can make the decision of whether I want my own lisp
style to be more functional, more imperative or whatever.
Most people coming from lisp will have another language under their
belt (is this a dangerous assumption?) and should shudder at the very
thought of common use of global variables. Would I use as many in my
code? I really hope not. However, a lot of code out there is written
that way and thats what I want to get from a beginning lisp book.

I do not want to give the impression that being technically correct is
not important. It is very important.
The book does need to be kept in a context though.

I don't think there would be any harm in posting the code on a thread
and asking people what they thought about it. There might be some old
school lisp hackers out there that could put a "lispy" outlook on what
they consider as important / unimportant when they write these sorts
of functions.
The different perspectives people had would give us all a greater
insight and we would all learn something from it which at the end of
the day is what it is all about.
Reply all
Reply to author
Forward
0 new messages