Hugh Aguilar <
hughag...@yahoo.com> wrote:
> Can you elaborate on the functional-programming mindset?
Writing functional programs means to write functions and then
combine them. All non-trivial functions are divided into trivial
(non-recursive) and general (recursive) cases. For instance, to
reverse a list, you would:
- map the empty list to the empty list: () ==> ()
- append a list containing the first element to the reversed rest
of the list:
(first rest ...) ==> (reversed rest ...) + (first)
In Scheme: To reverse a non-empty list LST using MY-REVERSE:
(append (my-reverse (cdr lst)) (list (car lst)))
Full program:
(define (my-reverse lst)
(if (null? lst)
'()
(append (my-reverse (cdr lst))
(list (car lst)))))
Another example: To find the maximum of a list:
- assume that the first element (X) is the maximum
- if the rest of the list is empty, return X
- if the first element E of the rest is larger than X,
return the maximum of E and the rest of the list
- else return the maximum of X and the rest of the list
In Scheme:
(define (maximum x . rest)
(cond ((null? rest)
x)
((> (car rest) x)
(apply maximum (car rest) (cdr rest)))
(else
(apply maximum x (cdr rest)))))
Notes: (maximum x . rest) decomposes the arguments of MAXIMUM
into the first argument X and a list named REST containing the
rest of the arguments.
(apply maximum x lst)
calls MAXIMUM with the arguments [plural!] (cons x lst).
So every function maps some arguments to a value. You write programs
by combining functions. Browse
http://www.t3x/org/s9fes/lib.html
for some more complex examples.
You then proceed to higher order functions, i.e. functions generating
functions, mapping, folding, etc.
For instance, you might want to write a minimum function and notice
that it differs from MAXIMUM only by single character. So instead
of copying 99% of the code, you write a function that generates
both MINIMUM and MAXIMUM:
(define (make-minmax pred)
(define (minmax x . rest)
(cond ((null? rest)
x)
((pred (car rest) x)
(apply minmax (car rest) (cdr rest)))
(else
(apply minmax x (cdr rest)))))
minmax)
(define minimum (make-minmax <))
(define maximum (make-minmax >))
Most importantly, though: acquiring the "functional mindset" cannot
be done by just reading about it. Try to solve some problems in the
functional way! Fetch a book, read about the basics, solve some
simple problems, like appending lists, reversing lists, finding the
greatest common divisor, etc.
Then solve a few more complex problems (generate the combinations
or permutations of a string, implement mergesort, etc). Next write
a few small programs by combining functions, then write larger
programs. Feel free to look at above URL for inspiration, but DO
try to find your own solutions!
Finally, learn to recognize functional patterns, like mapping and
folding, and use the appropriate higher-order functions. Keep
practicing. Nothing else will get you anywhere!
> My understanding of functional-programming is that we want to write
> functions that use only the data that is passed into them, rather than
> global data.
Yes, global state is used only when necessary. But Scheme code *does*
use global state when it makes sense. We do not try abstract everything
away at the function level.
> [...] Also, it is best to write short functions that do
> only one thing.
Factoring is a good thing but there is not need to make a religion
out of it. Don't be afraid to write functions that span multiple
pages, if it makes sense.
> Avoid functions that contain an IF (or worse, a CASE)
This is not FORTH. IF, COND, and CASE are used frequently.
> I never liked printf in the C language.
Well, we have FORMAT, [1] which is much more entertaining! It can
even do conditional evaluation and iteration.
[1] it's actually a Common Lisp thing, but many Schemes also have it.
> [...] Each of those Forth
> functions is short and simple, and it does one thing, and you put them
> together to do a complicated thing.
In Scheme a function also does one thing, but that "thing" may be
quite complex, like compiling a regex. (See for example,
http://t3x.org/s9fes/regex.scm.html)
> By comparison, printf is
> monolithic. It has never been tested thoroughly in the many decades
> since it was written --- there are way too many possible input
> strings.
Don't have a look at FORMAT, then.
> I'm interested in Gambit because I want to use the available C
> libraries, but I don't really like C itself. I've worked as a C
> programmer, and I've seen some *ugly* C code, such as functions of 100
> lines or more. Hopefully in learning Scheme I won't run into any
> monsters like that. :-)
You can write ugly code in any language, and it has been done in
Scheme, too. It is up to you what you make out of it.