On Sun, Jan 13, 2008 at 09:04:10PM -0800, [EMAIL PROTECTED] wrote:
I'm trying to understand first few pages of SICP where they explain
Scheme basics and had some newbie questions about evaluation....
** First of all, whenever you define a new function, the function's name and
function's code are stored in the "global environment". I thought
functional programming meant you weren't allowed to have any state. Yet,
modifying a "global environment" means changing state!?!?!?
First off, creating a new definition doesn't keep you from being
functional. Nobody could have looked at the definition before you defined
it, and as long as you don't change it's value, you can still be
functional. Without creating these bindings, it would be hard to get
anything done.
There are several kind of distinct things that people mean by functional
programming.
- Not having any state. This is sometimes called "pure" functional
programming. Scheme is _not_ a pure functional language.
- Encouraging programming by manipulation of functions. Lisp languages
certainly do this more than many other languages.
So, you're not going to learn how to completely avoid state by programming
in scheme. In fact, scheme programs tend to be just as imperative as
programs in a so-called imperative language.
As we get further along, we can get into languages that have partial
evaluation of functions, and how that much more encourages functional
programming.
As a simple example. I've been re-writing my file integrity scanner in
Common Lisp (it's a good sized problem to seriously learn a language).
I've implemented this in probably a half dozen languages. These vary a lot
in how much I will manipulate functions in my code.
- An imperative OO style language, such as Eiffel: no function
manipulation at all.
- A mostly OO language that has lambdas, such as Python: I might have one
that I pass to a sort routine, for example.
- Common Lisp: I probably will have a handfull, but not a lot. You have
to explicity mention something as a function in lisp (either with
lambda, or #'). Lisp is still very much an imperative or OO language.
But it has closures so you can do functional things when needed.
- Scheme: Since the base scheme has no OO, a lot of what you would do
with OO on Common Lisp would be done with functions. I would describe
Scheme as "more functional" than Common Lisp.
- Haskell: Haskell is pure. There is state. Actually, that's not really
true. They play a game where basically the state is always passed
forward through things. The end result is a very controlled
manipulation of state in a completely functional language. It would be
rare to find more than a couple of lines in a row of Haskell that
weren't manipulating functions.
Even Haskell has the top-level bindings. However, there is no order or
notion of time to those bindings. They all are just bound that way by the
compiler.
** Does the evaluation of functions return some mysterious type of object?
What the heck is going on? For example, look at evaluation of "+"...
1 ]=> +
;Value 11: #[arity-dispatched-procedure 11]
"+" is a function. It's a little confusing of a message, but basically
it's a function that you can invoke.
This isn't actually quite true. There is a symbol table. The entry for
"+" has this function stored in it.
The simple rule in scheme is that a form consists of
- A number, string, and some other things: evalutes to itself.
- A symbol: It is looked up via various rules to get a value.
- A list of forms in parens: The first form must evaluate to a function
which is called (applied) to the given arguments. This is a function
call.
- Some other things we'll get to later.
Notice that the definition is recursive. Each of the things in the parens
is another form.
In scheme, there is nothing special about the first term in a function
call expression. It is often a symbol that comes from the global symbol
table, but it doesn't have to be. It could be a locally defined symbol, or
even another expression in parens that computes a function.
** Also, what is the type of "define"? You cannot evaluate "define" so it
can't be a regular function.
1 ]=> define
Notice that the rules above always look up symbols when they are
encountered. We need to have some way to define new symbols, or our
program couldn't be more than one (possibly large) expression based on
existing definitions.
Hence, special forms (pardon my lisp terminology if Scheme uses different
names for these things). 'define' is special in that it doesn't evaluate
it's arguments. Instead, it looks at them unevaluated and uses that to
make a definition. Depending on what the first argument looks like, it
might create a function definition, or it might evaluate the second
argument.
Macros are how the user can create definitions. I don't think Macros are
covered in SICP. But, the Scheme implementer had to create some of these
or we would never get anywhere.
Another very useful special form is "quote". What if I don't want to
evaluate an expression. I can use the quote special form to not evaluate
it:
> (quote (+ 1 2))
(+ 1 2)
This is used often enough, that there is a special shortcut. The above is
equivalent to:
> '(+ 1 2)
(+ 1 2)
Dave
--
[email protected]
http://www.kernel-panic.org/cgi-bin/mailman/listinfo/kplug-lpsg