[Date Index]
[Thread Index]
[Author Index]
Re: Re: declaring integers
*To*: mathgroup at smc.vnet.net
*Subject*: [mg13125] Re: [mg13063] Re: declaring integers
*From*: Joe Oswald <jaoswald at fas.harvard.edu>
*Date*: Tue, 7 Jul 1998 03:44:28 -0400
*Sender*: owner-wri-mathgroup at wolfram.com
On Sun, 5 Jul 1998, David Withoff wrote:
> I didn't understand your discussion here, and the parts that I think I
> understand don't seem to be correct. Perhaps if I describe my concerns
> you can offer some clarifications.
>
> > When one types "a + b" in most languages (e.g. Fortran, C, Lisp "(+ a
> > b)"), one is referring to a mechanical procedure where some item, named
> > a, will be added to another item, named b. The nature of that procedure
> > will depend on whether a and b are small-sized integers or
> > floating-point numbers, or rational numbers, or large-sized integers.
> > It also doesn't make much sense if a is a string and b is a number.
> > I.e., it matters what "type" the "variables" are.
>
> That is what happens in Mathematica too. If you enter a+b, that invokes
> a mechanical procedure that will depend on what a and b are.
Well, no. If a and b don't have defined values, nothing gets added. The
pattern is simply returned:
In[1] := a + b
Out[1] = a + b
I.e. nothing is really "added". You might say that this is what addition
"means" for things which are just symbols, but this misses my point,
which is that no "machine instruction for addition" is invoked.
Mathematica did some computation, but basically all to determine that
*nothing* should be done.
In Scheme, without any definitions
(+ a b) --> error a not defined
I.e. what happens is that Scheme *evaluates* all three subforms +, a, and
b. Well, + evaluates to a built-in procedure <do addition>, but the
evaluation of a fails because a doesn't have a value, so Scheme has to
stop.
>> In Mathematica, one actually is specifying a "pattern" Plus[a,b],
> Perhaps I have misunderstood this too, but this doesn't seem right to
> ...
> The expression a+b isn't a pattern unless it is used in one of those
> positions.
OK. I was a bit cavalier in my use of the word pattern, which is why I
enclosed it in quotes. But the fact remains that the computation above
was simply a matter of pattern-matching, and didn't involve any
addition.
> > One particularly notable result of this pattern-matching behavior is
> > that cited in the reference section of Wolfram's book, regarding
> > Apply:
> > Apply[Plus, g[a,b]] --> a + b
> I'm not understanding your concern here either. Although the Apply
> function in Mathematica and, for example, the "apply" function in Lisp
> or Scheme, aren't identical, they are certainly similar, and the
> differences don't represent anything fundamental. For example,
Here I disagree. I believe the difference is something fundamental, and is
essential to what "apply" is used for in Scheme.
> (apply + '(2 2))
>
> in Scheme is equivalent to
>
> Apply[Plus, {2, 2}]
>
> in Mathematica.
Yes, but one would never use quote in the argument to apply! (I assume
that you mean a forward quote ', and not a backquote, which as far as I
know isn't used for Scheme, but in Common Lisp, refers to a more
elaborate quoting that, in your example, gives the same thing.)
This is a toy example, of course, because one would write
(+ 2 2), just as in Mathematica one would write Plus[2,2] or 2+2
so you might say our disagreement is over superficial things. However,
(apply + (2 2)) --> error 2 is not a function in (2 2)
would be a closer simulation of Apply[Plus, {2, 2}], and you see the
comparison starting to break down.
> One of the differences is that the Apply function in Mathematica replaces
> the head of the expression (the "car" in Scheme), while the "apply"
> function in Scheme includes the "car" as one of the arguments. That is,
> (apply + `(g a b)) becomes (+ g a b) while in Mathematica
> Apply[Plus, g[a, b]] becomes Plus[a, b]. Additional arguments are
> also treated differently, but not in a way that reflects fundamental
> differences between the languages.
There are fundamental differences.
1) There is no concept of "head" in Scheme!! In Mathematica, the concept
of "head" is necessary for pattern matching to be used in the
evaluation *all* expressions. "car" is a function which acts on *cons
cells* NOT on code. The fact that one can transform cons cells to code
by using "read" and "eval" does not make code and cons cells the same.
The first element of a Scheme form (f a b) typed into the
read-eval-pring loop is evaluated differently, but does not "stick
around" as a head. It is replaced by a procedure, defined as the value
corresponding to the symbol f, or returns an error if f is not defined.
Furthermore,
(apply + '(g a b)) --> error g is of type symbol in (+ g a b)
is not a useful thing to write in Scheme, because "g" "a" and "b" are
not things that can be added, since they are *symbols.*
...[I introduced an example using Apply]...
>
> Again, unless I have misunderstood something, I don't think this is true.
>
> While it is correct that (g a b) in (apply + (g a b)) will refer to
> a procedure g that will be evaluated before applying +, the same
> is true of Mathematica. That is, the g[a, b] in Apply[Plus, g[a, b]]
> refers to a procedure g that will be evaluated in Mathematica before
> Plus is applied. This evaluation order is used by all of the programming
> languages that you mentioned, and is described for Mathematica in the
> section 2.5 and appendix A.4 of the reference manual.
But if g is not yet defined, Mathematica keeps it as a symbol forming
the head of an expression. In Scheme, g is a symbol which is evaluated
to, hopefully, return an internal procedure object. If not, you are
asking the computer to **do** "g" where "g" is something it doesn't
know how to do yet!!
Notice that Mathematica doesn't assume you have asked it to *do* anything.
g[a,b] will simply give you g[a,b], if g, a, and b has no patterns
defined.
> Also, since (g a b) might be quoted, as in (apply + `(g a b)), it isn't
> entirely true that this procedure will always be evaluated in Scheme.
> The purpose of quoting in Scheme is to inhibit evaluation.
g is a symbol. '(g a b) is a textual representation of a list of three
symbols, g, a, and b. Adding symbols, which is what you are doing in
this example, is not defined in Scheme.
You seem to me to be confusing the textual representation of code in
Scheme with the code that it represents. In an unquoted form which has
the *textual representation* (g a b), the symbol g is evaluated to an
internal function object, a is evaluated to return some number, and b
is evaluated to return some number, and then the internal function
*named* g is applied to the arguments *named* by a and b.
It is very important to make and keep the distinction between the name
and the thing named. This is fundamental in Scheme, as well as
philosophy.
A similar
> effect can be achieved in Mathematica using Unevaluated. That is,
> Apply[Plus, Unevaluated[g[a, b]]] will apply Plus to the arguments a and
> b even if g[a, b] might otherwise evaluate to something other than itself.
>
> > I think the desire to "declare variable types" arises from an
> > underlying desire to program Mathematica in a procedural or functional
> > way. However, Mathematica is, at its heart, a pattern-matching system.
> > Whether that is better or worse than a functional or procedural style
> > depends on both the particular problem you are trying to solve, and on
> > your particular aesthetic approach to problem solving.
>
> Actually, Mathematica at its heart is a functional language, much like
> Lisp or Scheme. Pattern matching is the mechanism that is used for
> locating procedures, but it isn't used in any non-trivial way in the
> examples that you mentioned. Your comments seem to be about evaluation
> order rather than about pattern matching, but evaluation order is
> essentially the same in Mathematica as it is in most other languages,
> and the connection between these things and variable typing escapes me.
If you compare Mathematica's evaluation order to that of Scheme, one
find that Mathematica "keeps evaluating until nothing changes." [Or at
least tries to, but makes some heuristic guesses to help performance],
whereas in Scheme, there is no similar notion.
Also, most function definitions in Mathematica are defined using
patterns. E.g. g[a_,b_] := a Minus[a,b] *is* a pattern, so pattern
matching is used even when you just want functional code.
(define g (lambda (a b) (* a (- a b))))
doesn't invoke a pattern matcher when you write
(g 3 5) in Scheme.
Here is a demonstration of what I found confusing, comparing Scheme and
Lisp.
; example in Scheme
(define g (lambda (first second) (list first second)))
(define a 5)
(define b 3)
(apply - (g a b)) --> 2
; because (g a b) returns a list (5 3)
(define g-reversed (lambda (first second) (list second first)))
(apply - (g-reversed a b)) --> -2
; because g-reversed returns a list (3 5)
(* In Mathematica *)
a = 5; b = 3;
Apply[Minus, g[a,b]] (* oops, haven't defined g yet *)
--> 2 (* well, I don't notice *)
Apply[Minus, g-reversed[a,b]] --> 2
(* Hey, what's going on??? g and g-reversed give the same answer.
OHHHH!!! I don't have a definition for g-reversed yet. *)
g-reversed[first_,second_] := List[second,first];
Apply[Minus, g-reversed[a,b]] --> -2.
Of course, these are toy examples, but if the Apply hadn't been typed at
the interaction level, but was hidden behind some other code, you might
have a very hard time figuring out that you had forgotten to define g
or g-reversed, when your code didn't work as you expected!!!
It is interesting that the example given in the reference for Apply is
Apply[Plus, g[a,b]] --> a + b
When this is *completely* contrary to how "apply" is used in Scheme. In
fact, you *cannot* write this in Scheme. And the reason is far deeper
than "Scheme apply discards the head, while Mathematica apply keeps the
head".
If g isn't defined, you aren't specifying a computation with g[a,b],
but Mathematica doesn't mind. That is an advantage if you want to do
symbolic mathematics. In Scheme, however, you are writing functions to
do computations, not create symbolic patterns.
I think this represents the essential difference between Mathematica
and a functional language like Scheme:
1) The Apply routine was defined to superficially resemble Scheme
"apply" but the semantics in the example don't exist in Scheme. What
apply does in Scheme involves *INTERNAL PROCEDURE OBJECTS* whereas in
Mathematica, it does surgery on the internal list form of the things it
is passed. By the time Scheme's apply gets to work, the external
textual representation of a list does not exist any more.
2) The distinction between the internal representation of a thing and
the external representation of a thing is very different in Lisp/Scheme
and in Mathematica. That is essentially what I mean when I say that
Mathematica is always using "patterns". The representation of g[a,b] is
very literally something that is labelled with a head g and has a two
element tail containing a and b. In Scheme (g a b) *doesn't* represent
any particular internal representation. It describes a *computation*.
--Joe Oswald
(Aside)
Incidentally, many people with only a superficial knowledge of Scheme
or Lisp miss the point of (2). They get the idea that "a program in
Lisp/Scheme is a list of atoms."
In fact, Lisp code is written on the page in the same way that lists
of atoms would be written on the page; to some extent, this is
superficial. In C, a C program is written as a text file. The compiler
takes that text file and changes it to executable code. But the text
and the code are different things! One could write a different looking
text file in Pascal or in Scheme that could result in the same code.
Of course, the resemblance of Lisp code and Lisp data types makes it
easy for Lisp programs to write other Lisp programs. C programs that
write other C programs can exist, but they are seen as obscure. In
Lisp, they are seen as quite ordinary.
--Joe
Prev by Date:
**Re: Fibonacci**
Next by Date:
**Re: Re: Better WorldPlot data?**
Previous by thread:
**Re: Re: declaring integers**
Next by thread:
**Re: Re: declaring integers**
| |