MathGroup Archive 1998

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Re: declaring integers

  • To: mathgroup at smc.vnet.net
  • Subject: [mg13157] Re: [mg13063] Re: declaring integers
  • From: Joe Oswald <jaoswald at fas.harvard.edu>
  • Date: Mon, 13 Jul 1998 07:42:07 -0400
  • Sender: owner-wri-mathgroup at wolfram.com

On Tue, 7 Jul 1998, David Withoff wrote:

> My first question is about the connection you mentioned between declaring
> variable types and whether or not Mathematica is considered a functional
> language, a procedural language, or something else.  I don't understand
> what you mean by that.  These seem like orthogonal issues to me.

What I meant is that, in a functional language, using Scheme as a
description

  (foo a (bar b)) 

Results in a procedure object, named foo, which consists of machine
code, being executed, with two values "on the stack" or wherever
paramaters are passed. That code takes the two values, does something,
and puts a value "on the stack" and exits. If it is enclosed in another
form, then that form takes the value on the stack and keeps going.
That's a complete description of "foo".

It so happens in this example, that the second value came to be "on the
stack" because of another piece of code, which is part of the bar
object, being executed.

But "foo" doesn't know that! It just takes values and foos them.

As we discussed in e-mail, 

Plus[Times[2,a],a,b] --> Plus[Times[3,a],b]

Which means that Plus knows that Times[] was enclosed. 

The distinction is that, for my "foo" example, it makes sense to talk
about those values "on the stack." In that, they are a certain size, or
are in a floating-point register. Or, in a language like scheme, they
could be many different types, where the type is marked in some "magic"
way.

In the Plus[Times[]] example, one can't really talk about the value
being added. What type is Times[3,a]? It's a symbolic expression. It
doesn't correspond to a piece of computer code with a MUL instruction.
It would have some particular numerical type if we gave "a" a numerical
value, perhaps, but I can't tell you whether the CPU will do a MUL or
an FMUL instruction to compute it.

(As you mentioned in your e-mail, it would probably be better to
associate this behavior with a "rule" for Plus, when not dealing with
arguments that satisfy NumberQ, rather than "pattern" as I was in my
previous posts.)

> 
> My second question regards your comments about frustrating or puzzling
> behaviors, or behaviors that are otherwise not what you want.  I am not
> questioning that you may have had difficulties.  What I am questioning
> is what I read as the implication that these difficulties are the result of
> some intrinsic characteristic of the Mathematica programming language.
...
> aesthetic preferences, learning a new programming language, or switching
> from one language to another.

I've tried to be (with some help from the moderator) impartial and
objective in my analysis. What I mean is that I, like everybody, have
certain "models of computation" in my head. I happen to have been doing
a lot of programming in Lisp, so I've grown accustomed to using a
mostly functional model of approaching problems. The most common thing
to do in a functional language is to take a function and "apply" it to
some list of arguments.

I found myself with a list of anonymous functions which I wanted to
apply to a given argument, in order to end up with a list of the
results.

E.g. {Sin[#1]&, Cos[#1]&,.....}[3.14]  --> 
     
     { 0.0, -1.0, .....} was my goal.

However, my idea didn't work.

OBSERVATION 1: 

  Hmm. I expected the function application  ...[3.14] to map
automatically across the list, just like {1,2,3} + 4 --> {5,6,7}. 

MORAL: blah[3.14] "function application" doesn't act like +. In Lisp,
apply and + are equally valid functions.

   Ok. So I need to write some "apply1" function that will apply a
function to a single argument, and then map apply1[3.14] over the list.

In Common Lisp, I would write

(defun apply1 (arg) 
  (lambda (f) (funcall f arg))

(mapcar (apply1 3.14) (#'sin #'cos .....))

or, more compactly, 

(mapcar #'(lambda (f) (funcall f 3.14)) (#'sin #'cos ....)) 

OBSERVATION 2. Mathematica doesn't have funcall. Well, apply would do
the same thing if given a list '(3.14)

Hmm. I try various definitions of apply1 with Apply and get error
messages or unexpected behavior of various mysterious kinds. Most
particularly, I can't seem to do this using anonymous function notation
alone.

Hmmm. Maybe Apply is not the right thing. Let's look at the
documentation for Apply. WHAT THE HEY?  Apply[Plus,g[a,b]] --> a +
b???? That isn't what I was looking for. I want to put something in for
g, which will give me a list of arguments {3.14}.  If Apply "kills off"
g, this won't work. This looks like trouble.  Let me try it. 

g[a_] := List[a];
Apply[Sin, g[3.14]] --> 0.00159265

That seemed to work. (I can even tell the number is right, to first
order, because I can expand the Taylor series around x=Pi). Maybe the
documentation is wrong.

Apply[Sin, blah[3.14]] --> 0.00159265

Hmm. The documentation *is* right. I struggle through some other
examples and realize that blah[3.14], because and ONLY because,
blah[x_] is not defined, remains as blah[3.14], Apply does the surgery,
and then I get Sin[3.14]. Whatever Apply does involves surgery on the
arguments. 

OBSERVATION 3: Apply can potentially do "surgery" on arguments. Watch
out.

Anyhow, it turns out that my problem was with anonymous (#n,&) function
notation. I give up trying to do it all anonymously and end up with

apply1 := Function[arg, Apply[#1, List[arg]]&]

then I use it

extraplist = Map[Apply[fit90clip[#1, #2, 0.0]&, #1]&, lin3ft]; t0ex0 =
Map[apply1[0.0], extraplist];

Hooray! this does what I want. It only took me an hour to figure out
what I would have gotten in Lisp on the first try!

OVERALL OBSERVATION, after some reflection,

  Mathematica's use of f[] notation for "function application" really
only turns into a function call under the right conditions. (E.g.,
Plus[] with numerical arguments) Otherwise, f[] notation activates
"rules" on f, which might end up with a symbolic result. Apply[] works
in Mathematica by doing this surgery, because Apply[f,{a,b,c}] depends
on {} actually corresponding to a "head" of List. So when I write
square brackets, I have to remember that this isn't like a function
call in C or Scheme.


> 
[example where scheme gives an error instead of the same answer as
Mathematica, because of a difference between Apply and apply]

I wasn't really trying to compare actual programming in Scheme or
Mathematica, because the examples would be much too large. The point
was that the "rule-based" interpretation means that Mathematica has
different semantics than Scheme, as you elaborated in your e-mail to
me.

> while it illustrates a difference between Scheme and Mathematica, does
> not show a difference that would make any program more difficult in
> Mathematica than it is in Scheme, unless you happen to be relying on
...
> translated into Mathematica, which makes Mathematica a superset of
> Scheme in this regard.

Well, there are more different kinds of notation in Mathematica, but I
wouldn't call this a "superset." Mathematica does something different.
I'm not sure semantic differences can really be classified this way. 
Mathematica doesn't have first-class continuations. (for the audience: 
read Friedman's Principles of Programming Languages if you don't know
what this means. Prepare to have your mind blown.) Does this make
Scheme a superset of Mathematica?
 
    Scheme is precisely designed to have the *absolute minimum* of
    features needed to support "elegant" computation, so most languages
    are supersets of Scheme in one way or another! :-)

[examples of Scheme apply] 
[quotes in Scheme discussed]

> both quotes are used in Scheme (see for example "The Scheme Programming
> Language" by R. Kent Dybvig), and it is quite common to use quote
> in the argument of apply.  In fact, the very first example of "apply"
> in the aforementioned reference uses a quote (and proper quoting would
> also make your "(apply + (2 2)) --> error" example work).

I don't have Dybvig's book, but the fact that it is the first example
doesn't surprise me. It certainly doesn't represent how apply is
actually *used*. (apply + '(2 2)) is not "proper quoting." It's just a
verbose way to write (+ 2 2).  I can't think of a single *useful* way
to use quote on the second argument of apply, outside of a textbook
example. 

Just as in Mathematica Apply[Plus, {2,2}] is just a toy example--no one
would do this, because it is just Plus[2,2]. NOTE, however, that this
simple example only works because {2,2} is an input form for for
List[2,2].

[another example omitted]
[Scheme - is equivalent to Subtract[], not Minus[]] [Mathematica doesn't
allow names like g-reversed]

Sorry, I was typing this without Mathematica around. Lisp & Scheme both
allow - in a name.

> You have identified one legitimate complaint about Mathematica -- that
> it would be convenient for some purposes if Mathematica would warn you
> when you forget to define a procedure.  This difference between Scheme
> and Mathematica doesn't affect programs that work, but the warning
> message can be a useful diagnostic tool for programs that don't work.

I'm not trying to identify complaints about Mathematica (although I have
them :-)), just trying to explain that differences between Mathematica
and other languages can cause trouble for someone with expectations
based on those other languages.

> Regarding patterns, not only are patterns not a fundamental part of
> Mathematica, you don't even need to use patterns at all in Mathematica
> if you don't want to.  The translation of

I concede that when I said "patterns" I wasn't using your terminology. I
included in "patterns" what you seem to call "rules".

> (define g (lambda (first second) (list first second)))
> 
> into Mathematica is
> 
> Set[g, Function[{first, second}, List[first, second]]]
> 
> which doesn't use patterns any more (or less) than Scheme uses
> patterns.  In Mathematica you could also use
> 
> g[p_, q_] = {p, q}

Well, let's compare. 

Set[g1, Function[{a,b}, List[a,b]]];

g2[p_,q_] = {p, q};


and, later, if you make a mistake, or forget which way you defined g.

g1[a,b,c] --> {a, b}
g2[a,b,c] --> g2[a,b,c]

So these aren't the same thing after all. Sure, this is going beyond
what we've defined, but I certainly can't say why these two results are
different. At least, not based on my experience with any other program
or language. In particular, I'm not sure that the difference between
Function[] things and "functions" defined as f[p_,q_] as is most
common, is ever clearly set out in Wolfram's book. They both use square
brackets when they are invoked, though. 

> to define this procedure, which does use non-trivial patterns, but
> that just shows that Mathematica has functionality that Scheme doesn't
> have.  If you don't want to use that functionality, you can program
> Mathematica in much the same way that you program Scheme.

No, I can't. Please, I don't want to get into some contest about
"Mathematica has more functionality", or "Scheme has better
functionality." I am trying not to make a religious statement. But the
functionality is *different*.

I was just trying to show people that, in perhaps subtle ways,
Mathematica doesn't obey preconceptions one might have from other
languages.

> It is perfectly legitimate to prefer some language for aesthetic
> reasons, or because it somehow appeals to your way of thinking.  If
> you like Scheme because of some subjective feature, I could readily
> accept that.  If you want to argue that Scheme is objectively superior
> to Mathematica in some way, however, you have to do a lot better
> than that.  In particular, are there any essential features of Scheme
> (other than generating errors for undefined procedures) that you can't
> find in Mathematica?

Look, I'm trying not to "argue" at all, much less argue that Scheme is
"objectively superior" as if such a concept exists. My examples, where
Scheme gives an error message, were simply ways to show that
Mathematica has *different* semantics in these cases, since it doesn't
give an error message. The point of programming is not "hey, I didn't
get an error message, so things are all right." But "did I say what I
thought I was saying?" 

  And, as I said, Scheme is purposefully minimalist. At one point, the
Scheme standard was shorter than the *index* to a Common Lisp reference
book, which itself is thinner than Wolfram's 3d edition. Features
aren't everything, and Scheme has all that count, pretty much, to
express algorithms--some, like continuations, that don't exist in most
other languages.

--Joe



  • Prev by Date: Re: Derivatives D[ ] as Functions inside Tables; Need Help!
  • Next by Date: Re: how can I use greek letter and English letter in 1 cell
  • Previous by thread: Re: Re: Re: declaring integers
  • Next by thread: kernel problem