[plt-scheme] How do I do this in true functional style?

From: Joe Marshall (jrm at ccs.neu.edu)
Date: Wed Dec 1 10:08:29 EST 2004

Devlin Bentley <com2kid at gmail.com> writes:

>   For list-related administrative tasks:
>   http://list.cs.brown.edu/mailman/listinfo/plt-scheme
>
> I was mentally going over how I was going to write a mini wireframe[1]
> 3d-renderer in Scheme, and right afterwards I went and skimmed through
> parts of HTDP.  After finishing some reading in HTDP (and noticing
> that set! is not introduced until Chapter 34), I began to feel sick to
> my stomach with my current plan for doing my renderer.
>
> The way I was going to do it up until about 10 minutes ago involved
> taking a text file with comma separated integers and using each three
> sequential integers as indices in a 3-dimensional array of booleans
> when setting the read in index to true.

I don't exactly understand why you going about it this way, but I
suggest that a text file of comma separated values is suboptimal.
You'd have to write your own reader for it.

If you instead make the values separated by whitespace and delimited
by parenthesis, you can get the Scheme reader to parse it for you.
Additionally, you may wish to use the printed representation of the
desired 3-dimensional array of booleans.  This will avoid the entire
process of initialization.

> The actual drawing algorithm would then traverse the array (also an
> icky hack that should not be done, nexted for loops in Scheme just
> because they are easy for my brain to think of....) and use a "next in
> line" function to jump between valid points.
>
> Now it'd all work, and take me an hour or two tops to code, but the thing is:
>
> - Lots of set-vector! statements being executed, tons of them.

This is, to some extent, a result of writing your own reading and
initialization code.  You *could* try to work out how to functionally
create your boolean array from a list of values, but I don't think
it'd be much easier.

> - Hacked on nested iterative loops (I've already programmed this in
> before, it looks horrible and feels "obviously wrong", not a recursive
> algorithm at all!)

Don't worry about this too much.  When you are working in a
3-dimensional space, you should expect to see 3-dimensional nesting.
Remember, iteration is simply a special case of recursion.

> - I seriously get the feeling that my solution is best suited for a
> more procedural language.  (Not surprising considering I originally
> wrote it out in procedural psuedocode)

I disagree!  I think the fact that you wrote it in a procedural
pseudocode caused you to head down a procedural path.  (And I *HATE*
pseudocode!)

> How am I approaching this wrong?  My instructor doesn't really care
> how it gets done (The final "fun" assignment of the quarter is to draw
> something, anything, in 3D) and no matter how I do end up doing it, it
> will be fun having a little mini 3d room rendered on my screen, but I
> will feel a lot better about it if I can have a true recursive (and if
> possible functional!) solution.

Don't worry too much about the functional `purity' of the solution.
Just get the assignment done and have pretty pictures.  Once you have
that, *then* review what you are doing and redesign it.  You'll start
to see places where you could have used a more functional style.  With
practice, the functional style will be more obvious to you.

> Is this even possible given that I need to read in data from a text file?

Yes.  I have a trick for reading non-lisp text files:  pre-convert the
file to a lisp format.  This is usually pretty trivial.  I use Emacs
macros, SED, AWK, LEX, or whatever to strip out noise like commas and
put in parenthesis, quotations, etc.  It is cheesy, but really
effective.

> Aside from converting the text file into one gigantic list and parsing
> through it, is there any way for me to get around using a million and
> one sets, or are situations like this considered times when it is
> "acceptable" to use mutators?

Mutators themselves aren't `unacceptable'.  What *is* unacceptable is
the implicit dependencies between objects and implicit dependencies
upon time that occur all too easily when you use mutators.  Using a
purely functional approach sidesteps all the problems with mutators.
It is easy to generalize this into `Functional, good.  Mutators, bad.'
but that isn't entirely accurate.

If you find yourself mutating structure, you should consider the
drawbacks.  In this case, you are mutating a structure in order to
initialize it.  This means that you have introduced the possibility of
uninitialized or incompletely initialized structure.  Without
mutators, uninitialized structure could never become initialized, and
would therefore be useless.  Furthermore, structure creation would
need to be able to create fully initialized structure, so
uninitialized structure would be either logically impossible or
the result of a deliberate instantiation.

Avoiding the use of mutators avoids the problem of uninitialized
structure, but there is another way to avoid the problem.  If you
confine the use of any uninitialized or partially initialized
structure to the one function that needs to create and initialize the
structure, then you also don't have to worry about uninitialized
structure in the rest of your program.




Posted on the users mailing list.