MathGroup Archive 2005

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

Search the Archive

Re: Re: Re: Types in Mathematica

  • To: mathgroup at smc.vnet.net
  • Subject: [mg62909] Re: [mg62872] Re: Re: Types in Mathematica
  • From: "Steven T. Hatton" <hattons at globalsymmetry.com>
  • Date: Thu, 8 Dec 2005 00:05:14 -0500 (EST)
  • References: <dn22fb$kum$1@smc.vnet.net> <200512070411.XAA23826@smc.vnet.net> <F505B3D5-9BCD-49F6-A894-D997D33F5C6D@jeol.com>
  • Sender: owner-wri-mathgroup at wolfram.com

On Wednesday 07 December 2005 10:54, Sseziwa Mukasa wrote:
> On Dec 6, 2005, at 11:11 PM, Steven T. Hatton wrote:
> >> Fair enough but Head[{1,2,3}] is not Symbol.
> >
> > I would say that we have to be clear about what we mean by "Head
> > [{1,2,3}]".
>
> I meant the value of evaluating the expression.

In[1]:= Head[Head[{1,2,3}]]

Out[1]= Symbol


> I don't know why, it simply betrays Mathematica's LISP like roots,
> and as Daniel Lichtblau pointed out is to be read more as a model for
> reasoning than as to how Mathematica is actually implemented.  At any
> rate in the purest forms of LISP that's all one has an atom, which is
> defined as an indivisible S-expression and a list which is an S-
> expression of two parts the first is called the head or car and the
> second a pointer to the rest of the list. 

Hmmm.... That's a very interesting statement.  In reality, at that level of 
detail the description of a Mathematica expression is distinct from the Lisp 
model.  Mathematica expressions are described as being arrays of pointers to 
other Expressions.

Lisp:

[data|link]->[data|link]->[[data|link]|link]->...
                                   |->[data|link]->...

Mathematica:

[link|link|link...]
  |     |   |->[link|link|link...]
  |     |->expression       |->expression
  |->head


> > In any case, (I believe) the leaves of an expression will be atoms
> > of one
> > kind or another.  The atoms are (AFAIK) the only entities in
> > Mathematica
> > which hold data.
>
> Heads have values too, an atomic expression is simply one which you
> can't take apart any further, but the atomic expression 1 has a head
> in Mathematica and the head has a value.  The fact that we display
> and write 1 instead of Integer[1]  is syntactic sugar as far as I'm
> concerned because at that point we are typically more interested in
> the interpreting Integer[1] as a value which is the result of some
> computation which is really what one is interested in.


In[2]:= Integer[1]===1

Out[2]= False


In[3]:= Attributes[1]

Attributes::ssle: 
   Symbol, string, or HoldPattern[symbol] expected at position 1 in 
    Attributes[1].

Out[3]= Attributes[1]


> > there are clearly different types of atomic expressions.
>
> Especially if you consider the heads of atoms as defining their type,
> which is why I think that is a useful paradigm for reasoning about
> types in Mathematica.

I would say that the distinction has more to do with their fundamental 
characteristics than with the name or symbol attached to them.  In 
particular, the kinds of data they store.

Head[Symbol]
SymbolName[Symbol]

Head["string"]
Characters["string"]

Head[12345]
IntegerDigits[12345]

Head[10/3//N]
RealDigits[10/3//N]

Head[25/17]
Numerator[25/17]
Denominator[25/17]

Head[E^I GoldenRatio//N]
Re[E^I GoldenRatio//N]
Im[E^I GoldenRatio//N]


> The fact that Head[Sqrt[2]] isn't Sqrt as Jon 
> Harrop pointed out seems to me more an artifact of the evaluator than
> a problem with Mathematica.

There are countless examples of this kind.

In[8]:= Head[Subtract[a,b]]

Out[8]= Plus

In[9]:= Subtract[a,b]//FullForm

Out[9]//FullForm= Plus[a, Times[-1, b]]

Regardless of whether you consider the head of the expression as representing 
a "type", that is a very tricky aspect of Mathematica.


> However the expression Integer[1] is represented internally, and for
> efficiency's sake it's hard to imagine that it occupies multiple
> words of machine storage, is irrelevant as to how one should reason
> about Mathematica programs.  It's also irrelevant that the Notebook
> Interface displays it as 1 instead of Integer[1].  The question is
> whether one can reason about a program correctly, it seems to me
> ambiguity can be best avoided by understanding 1 to be a) atomic and
> b) representing Integer[1].

See the examples above regarding Integer[1].

> >>> What confusion?
> >>
> >> The confusion over exactly what constitutes a type in Mathematica.
> >
> > Since there is no formal definition, it is strictly a matter of
> > opinion,
> > and/or convention.  Since there seems to be little in the way of
> > commonly
> > agreed upon convention, we are stuck with relying on opinion.
>
> But as you pointed out yourself Wolfram documents exactly what
> everything in Mathematica is in A.9.2, it's an expression.

I don't believe I suggested that A.9.2 documents exactly what everything is.  
I've been rather clear that I do not find the documentation complete.

> Some 
> expressions are atomic, and if you want to assign a "type" to the
> atoms other than expression the best candidate I can see is the head.

That's what Wolfram says in the appendix. "These [atomic] objects have heads 
which are symbols that can be thought of as 'tagging' their types. The 
objects contain 'raw data', which can usually be accessed only by functions 
specific to the particular type of object. You can extract the head of the 
object using Head, but you cannot directly extract any of its other parts."

> I don't think that matters.  The distinction that's important is
> between statements and expressions, LISP like languages do not have a
> statement type and it is that fact that allows "functions" to be
> treated as a first class types.

Function in C++ certainly have types.  They are not, however first class 
objects, nor objects of any kind, by definition.  C++, however does not have 
a statement type.  It has statements, but "statement" is not a type.  A 
statement is simply a syntactic unit of code.  People do use the term 
"statement" when discussing Lisp expressions.  In C++ the term statement 
means "the basic unit controlling the execution flow in a function, such as 
if-statement, while-statement, do-statement, switch-statement, expression 
statement, and declaration." Expression means "[a] combination of operators 
and names producing a value."  

That is why everything in Mathematica is called an expression. It will always 
"produce a value" when evaluated.  Indeed that's why people avoid terms such 
as "execute", and favor saying an expression is "evaluated".

But back to your original statement 

"You can't inspect the structure of the function in C++ because it's a
function definition and there is no facility for programmatically
inspecting the contents of a definition in C++.  In Mathematica the
contents are stored as an expression in the DownValues which can be
modified as any other expression in Mathematica sans restrictions."

How does that compare to rtti or having a virtual function table and using 
virtual funcitons to implement polymorphism?  You most certainly can get some 
internal information from an object that way.  If it happens to be a function 
object with public members?

> > Vector3f plus(const Vecotr3f& v1, const Vecotr3f& v1) {
> >   return Vector3f(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
> > }
> >
> > and
> >
> > Vector3f operaotr+(const Vecotr3f& v1, const Vecotr3f& v1) {
> >   return plus(v1,v2);
> > }
> >
> > Then write va + vb to add two Vector3f objects.  How does that
> > compare to
> > overloading + in Mathematica?
>
> It's roughly equivalent except in Mathematica I can programmatically
> rewrite the rules for + whereas there is no such facility in C++.  I
> suppose you can consider that an artifact of the fact that C++ is
> compiled (actually is that a requirement?  http://root.cern.ch/root/
> Cint.html)

That would not pass muster among 99% of C++ programmers.  85% implementation 
is abysmal in terms of whether it really is C++.  It is an interesting 
concept, as is JIT sans VM.  In both cases you /do/ have the luxury of 
modifying the code to be executed using the currently executing code.  It's 
something I've been suggesting for a while now.

> but I think the real reason for the difference is that 
> operator+ is a statement in C++ and there are no facilities for
> programmatically altering statements.

There certainly are at compile-time.  As a matter of fact that is the entire 
purpose and function of templates.  The are meaningless unless they are 
transformed into compilable specializations.

> > When trying to represent an ensamble of interacting physical
> > objects, I find
> > it useful to be able to maintain state.  In OOP that is fairly
> > straightforward.  This is why I like development libraries such as
> > OpenSceneGraph.  I've done similar things with Mathematica, but it
> > has not
> > been quite as easy.
>
> I've had similar problems, but usually I found that reorganization of
> the problem either allowed the writing of expressions that could
> compute a representation of state when necessary, and at no more
> expense than maintaining a state variable, or obviated the need
> altogether.  When translating programs implemented in other languages
> or interacting with such programs I've found that naively trying to
> use that paradigm in Mathematica leads to difficult to maintain code
> and often it's better to just rewrite the algorithm in a different
> style.  One example are divide and conquer algorithms for linear
> algebra problems.  Typically they are implemented with state
> variables that keep track of indices of submatrices and operations
> like multiplying a matrix against a submatrix of a larger one.  I've
> found that recasting the algorithm as functions which do basic
> operations and encasing them in structures like FoldList, Nest etc.
> which construct the final result from the submatrices leads to
> clearer, if not necessarily more efficient, Mathematica code.

That kind of code should be much more efficient than the "procedural" analog 
when written in Mathematica.  You can represent a lot of things in lists 
which would be represented in objects if implemented in C++.  It really 
depends on what you are trying to accomplish.  Some graphics problems are 
easily handles without using objects.  But OOP really is helpful when dealing 
with a lot of different graphical objects, especially if the objects can be 
grouped into classes.

> On the other hand, I've noticed a trend in OO graphics programs for
> defining 3 and 4D vectors and matrices as classes and then
> overloading +,-,* etc. which leads to inefficient code like
>
> t=a*b;
> d=c*t
>
> instead of
>
> d=a*b*c

There is no reason you cannot use the latter expression if you have overloaded 
* with something reasonable.  You can also use composite function objects 
which will blow the doors off of any Mathematica code you can dream up.  
Throw in std::valarray, and I don't believe you are going to encounter any 
limitations other than the speed electrons move in your CPU.  Mindyou, when 
you talk to C++ graphic programmers about performance they start counting 
instruction calls per operation.


> which is one of the problems that Blitz++ tries to address.  As we've
> both noticed Blitz++ addresses this problem by using C++ templates
> (and the CPP) to effectively convert statements to expressions which
> can be optimized for efficiency similar to the fundamental difference
> between operator overloading in c++ and Mathematica.

The real trick is to hijack the graphic processor for your own matrices, etc.  
I've never done it, but I've read about it.

Steven


  • Prev by Date: Re: Re: Re: Types in Mathematica
  • Next by Date: Mathematica Journal Back Issues Online Availability
  • Previous by thread: Re: Re: Re: Types in Mathematica
  • Next by thread: Re: Re: Re: Types in Mathematica