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