Why does it feel more procedural or un-functional?
A program is functional so long as procedures have no side-effects and
objects are not mutated. Your first example does neither, so it is
functional.
Remember, let* is equivalent to a sequence of lambda expressions:
(define (get-squares candidate)
((lambda (groups)
((lambda (chunks)
((lambda (square-groups)
((lambda (squares)
squares)
(map flatten (flatten x))))
(map (lambda (l) (split l 3)) chunks)))
(lump-n 3 groups)))
(split board 3)))
(I've just typed this in without checking, so chances are i've made a
mistake somewhere)
So really all you're doing is defining and executing a sequence of
lambda expressions. nothing's more functional than that! :-]
Perhaps you're worried because it looks too much like a sequence? In all
of these examples, (split board 3) has to be evaluated first, because
otherwise there's nothing to map on or flatten or whatever. (OK, so
technically the (lambda (l) (split l 3)) could be evaluated first...),
so there's going to be a sequence of events no matter how you write it.
Also, remember that map and higher-order functions aren't complusory:
they're there to make your life easier.
While Aaron's version is reasonably clear, in larger examples I think
often it's better to do things your way, using let* to name bits as you
go.
(define (otherwise things)
(lambda (can)
(end up
(being
(horribly embedded)
(lambda () (and (map rather (list difficult to follow) ;
(or (just plain))))
(confusing) ))))
Also, let* allows you to name each part of the computation, so hopefully
it will be clearer what every bit does. For example,
(map (lambda (l) (split l 3)) chunks)
Seeing that on its own for the first time gives me no inkling of what is
being done here. I mean, sure, something that splits stuff is being
mapped over some 'chunks' (which could be anything), but i don't know
why or what all this means.
Your first formulation tells me that this produces 'square-groups',
which starts to be a bit more helpful.
--
-arc.