f



Re: Re: Types in Mathematica #2

On Dec 4, 2005, at 6:16 AM, Steven T. Hatton wrote:

I started this reply before seeing your conversations with Kris  
Carlson, he seems to have better elucidated the points I was trying  
to make.

> On Saturday 03 December 2005 21:37, Sseziwa Mukasa wrote:
>
>> On Dec 3, 2005, at 6:52 PM, Steven T. Hatton wrote:
>> An example of a strong and
>> dynamic language is LISP, and this is one respect in which  
>> Mathematica
>> differs from LISP.
>>
>
> (setq f 1)
> (setq g 2.2)
> (setq h (+ f g))
> (print h)
> =>3.2

It's been a while since I used LISP, fair enough.  Whatever the case  
with respect to strong typing LISP is generally considered strong  
among computer scientists as far as I can tell.

>> C is of course weak and static, Java is strong and
>> static and that covers the four possibilities.
>>
>
> Java certainly supports primitive type conversion, so I don't  
> understand your
> statement.

Allowing type conversion isn't the issue (and real + int is a poor  
example) but we both agree it's a difficult concept to define  
unambiguously.  It also seems it's aside from the general discussion,  
this thread does not appear to be about whether Mathematica is strong  
or weakly typed but about what a type is exactly in Mathematica.

>> A List is most certainly not a Symbol, nor is it Complex, Integer,  
>> Real
>> etc.  A List is an expression whose Head is a Symbol with value List
>> applied to zero or more arguments.  Hence the idea that everything in
>> Mathematica is an expression, that's really the only type that exists
>> (and paradoxically in that sense Mathematica is strongly typed,  
>> but in
>> a universe with only one type it is impossible to distinguish between
>> strong and weak typing).
>
> I don't agree with this.

Fair enough but Head[{1,2,3}] is not Symbol.

>   One can say that 1 is an expression with head
> Integer, but to say that expression is a data type is not much  
> different than
> saying everything in C++ is a statement.

There are different kinds of statements in C++ of which expressions  
are but one class (http://cpp.comsci.us/syntax/).  There are no  
different kinds of expressions in Mathematica all have the same  
structure Head[Arguments...].

>> f[g[x_]] can be considered to be a function that acts on objects of
>> type g.  Since Mathematica is not strongly typed to ensure that we  
>> know
>> the pattern x_ is to be considered of type g we have to explicitly
>> include the information somewhere, and in Mathematica a convenient
>> location is the head of an expression.  It's not necessary to do it
>> that way f[{g,x_}] also works and now the type g is represented as a
>> list whose first element indicates its type.
>>
>
> How does that have superficial resemblance to the use of a type  
> system in
> another language?

Because there is no intrinsic type system to which I've added g in  
the sense that declaring a class in C++ adds an explicit new type to C 
++ along with int, double etc.

> What confusion?

The confusion over exactly what constitutes a type in Mathematica.

I will go out on a limb here and say there are two definitions of  
type in Mathematica.  One is of what type entities (the word objects  
has too many connotations to use in this context) in Mathematica are,  
to which the answer is everything is an expression.  The other  
definition is of how one defines a type hierarchy in Mathematica  
which defines objects and operations thereon, and the answer is there  
are multiple ways but the generally preferred way is to use the head  
of expressions to establish membership in the hierarchy.

> What is the difference between associating a function with an  
> operator in C++
> and in Mathematica?

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.

>> Because C++ has well defined constructs called, statements, functions
>> (or operators) and a host of types and a lot of rules explaining how
>> they all interact.  Mathematica has none of these.
>
> You are making assertions which are contrary to the terminology  
> used to
> discuss Mathematica.

For the sake of brevity and in the correct context clarity, it helps  
to refer to things like Plus[a_,b_] as a function or operator and For 
[...] as a statement but the truth is in Mathematica they are both  
expressions and equivalent in that sense.  Making the distinction may  
be useful to thinking about problems from the programmer's  
perspective but there is nothing within Mathematica itself that  
forces that distinction unlike in C++ where function+(a,b) and for 
(...){} are different.

I suppose though that this discussion thread would be helped by  
examples of where some particular definition of type is both useful  
to the programmer and difficult to implement in Mathematica.   
Personally I have found that objects which require complicated state  
information are not trivial to use in Mathematica but I have usually  
found that using a different perspective often obviates the need for  
state in the first place.  With respect to GUI like programs that  
don't lend themselves to the Notebook interface, this is not  
generally the case and as has been said many times on this list  
Mathematica is not suited to the writing of such programs.

Regards,

Ssezi

0
mukasa (387)
12/5/2005 6:55:39 PM
comp.soft-sys.math.mathematica 28821 articles. 0 followers. Follow

12 Replies
739 Views

Similar Articles

[PageSpeed] 33

Sseziwa Mukasa wrote:

> On Dec 4, 2005, at 6:16 AM, Steven T. Hatton wrote:

> It also seems it's aside from the general discussion,
> this thread does not appear to be about whether Mathematica is strong
> or weakly typed but about what a type is exactly in Mathematica.

Lets just say Mathematica is "loosely typed", and leave that term loosely
defined.

>>> A List is most certainly not a Symbol, nor is it Complex, Integer,
>>> Real
>>> etc.  A List is an expression whose Head is a Symbol with value List
>>> applied to zero or more arguments.  Hence the idea that everything in
>>> Mathematica is an expression, that's really the only type that exists
>>> (and paradoxically in that sense Mathematica is strongly typed,
>>> but in
>>> a universe with only one type it is impossible to distinguish between
>>> strong and weak typing).
>>
>> I don't agree with this.
> 
> 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}]". 
At one level, it is nothing but a sequence of characters.  When
Head[{1,2,3}] is evaluated, a downvalue is added to In

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

Out[1]= List

In[2]:= DownValues[In]  

Out[2]= {HoldPattern[In[1]] :> Head[{1, 2, 3}], 
 
    HoldPattern[In[2]] :> DownValues[In]}

It *could* be that the character sequence Head[{1, 2, 3}] is stored in the
symbol table entry for In with some mechanism used to indicate the
RuleDelayed.  From that observation, one might suggest that the only
"things" that really exist in Mathematica are symbols. 

A.9.2 in the 5.2 Mathematica Book says "A Mathematica expression internally
consists of a contiguous array of pointers, the first to the head, and the
rest to its successive elements."  I find that statement very incomplete. 
When I am finished typing Head[{1,2,3}], and before I evaluate it, it
certainly does not have any internal representation in the kernel.  The
kernel need not be running at that point.  After the input is evaluated, is
there still an internal representation of the expression?  Perhaps I am
wrong about how the DownValues of In are stored.  They may actually be
expressions as described in the appendix.

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.  The only way to access an expression is through some
symbol.  Expressions are composite data structures which form trees whose
subtrees are expressions, and whose leaves are atoms.  Now, by definition
an Atom is an expression, so you can say everything is an expression, but
there are clearly different types of atomic expressions.

>>   One can say that 1 is an expression with head
>> Integer, but to say that expression is a data type is not much
>> different than
>> saying everything in C++ is a statement.
> 
> There are different kinds of statements in C++ of which expressions
> are but one class (http://cpp.comsci.us/syntax/).  There are no
> different kinds of expressions in Mathematica all have the same
> structure Head[Arguments...].

How is that different from saying there are atomic expressions and composite
expressions in Mathematica?  Is 1 of the form Head[Arguments...]?  You may
be able to show that it is by playing with the definition for
[Arguments...], but to my way of thingking, 1 just /is/.

>>> f[g[x_]] can be considered to be a function that acts on objects of
>>> type g.  Since Mathematica is not strongly typed to ensure that we
>>> know
>>> the pattern x_ is to be considered of type g we have to explicitly
>>> include the information somewhere, and in Mathematica a convenient
>>> location is the head of an expression.  It's not necessary to do it
>>> that way f[{g,x_}] also works and now the type g is represented as a
>>> list whose first element indicates its type.
>>>
>>
>> How does that have superficial resemblance to the use of a type
>> system in
>> another language?
> 
> Because there is no intrinsic type system to which I've added g in
> the sense that declaring a class in C++ adds an explicit new type to C
> ++ along with int, double etc.

But that only says that whatever you did is not like C++ in so much as C++
has a formal definition of "type", and Mathematica does not.  It still
doesn't tell me how it has any resemblance to a type in C++.  I can create
a pseudo type system in C++.  It is not uncommon to find code that uses
such a mechanism, rather than using the builtin type mechanism.

>> 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.

>> What is the difference between associating a function with an
>> operator in C++
>> and in Mathematica?
> 
> 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.

But that really seems to rely on the fact that C++ is a compiled language,
whereas Mathematica is interpreted.  That is certainly an important
distinction.  I'm not sure why that distinction would be any more
significant when dealing with operators than in any other context.  I
believe there are important distinction between the way C++ and Mathematica
support operator overloading.

>>> Because C++ has well defined constructs called, statements, functions
>>> (or operators) and a host of types and a lot of rules explaining how
>>> they all interact.  Mathematica has none of these.
>>
>> You are making assertions which are contrary to the terminology
>> used to
>> discuss Mathematica.
> 
> For the sake of brevity and in the correct context clarity, it helps
> to refer to things like Plus[a_,b_] as a function or operator and For
> [...] as a statement but the truth is in Mathematica they are both
> expressions and equivalent in that sense.  Making the distinction may
> be useful to thinking about problems from the programmer's
> perspective but there is nothing within Mathematica itself that
> forces that distinction unlike in C++ where function+(a,b) and for
> (...){} are different.

I don't follow.  I can write a function 

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?

> I suppose though that this discussion thread would be helped by
> examples of where some particular definition of type is both useful
> to the programmer and difficult to implement in Mathematica.
> Personally I have found that objects which require complicated state
> information are not trivial to use in Mathematica but I have usually
> found that using a different perspective often obviates the need for
> state in the first place.  With respect to GUI like programs that
> don't lend themselves to the Notebook interface, this is not
> generally the case and as has been said many times on this list
> Mathematica is not suited to the writing of such programs.

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.  Part of the problem is that I really didn't understand
Mathematica well when I started using things such as Dr. Maeder's Classes
package.


-- 
The Mathematica Wiki: http://www.mathematica-users.org/
Math for Comp Sci http://www.ifi.unizh.ch/math/bmwcs/master.html
Math for the WWW: http://www.w3.org/Math/

0
hattons (214)
12/7/2005 4:34:39 AM
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.

> At one level, it is nothing but a sequence of characters.  When
> Head[{1,2,3}] is evaluated, a downvalue is added to In

That's a side effect of the evaluator, and can be suppressed anyway.   
I don't consider In and Out to be fundamental to the operation of  
Mathematica.  In fact their existences is one of the areas in which  
Mathematica breaks with being purely functional but that's another  
issue.  Others like Jon Harrop probably have far more intelligent  
things than me to say on that subject.

> A.9.2 in the 5.2 Mathematica Book says "A Mathematica expression  
> internally
> consists of a contiguous array of pointers, the first to the head,  
> and the
> rest to its successive elements."  I find that statement very  
> incomplete.

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.  I believe I read somewhere  
that Mathematica's representations of expressions are called M- 
expressions and were actually the intended syntax for LISP but for  
some reason S-expressions ended up being preferred.

> 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.

> 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.  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 different kinds of statements in C++ of which expressions
>> are but one class (http://cpp.comsci.us/syntax/).  There are no
>> different kinds of expressions in Mathematica all have the same
>> structure Head[Arguments...].
>
> How is that different from saying there are atomic expressions and  
> composite
> expressions in Mathematica?  Is 1 of the form Head[Arguments...]?

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].

>>> 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.  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.

>> 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.
>
> But that really seems to rely on the fact that C++ is a compiled  
> language,
> whereas Mathematica is interpreted.

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.

> I believe there are important distinction between the way C++ and  
> Mathematica
> support operator overloading.

I do too, but I don't think we agree on what the distinction is.

>> For the sake of brevity and in the correct context clarity, it helps
>> to refer to things like Plus[a_,b_] as a function or operator and For
>> [...] as a statement but the truth is in Mathematica they are both
>> expressions and equivalent in that sense.  Making the distinction may
>> be useful to thinking about problems from the programmer's
>> perspective but there is nothing within Mathematica itself that
>> forces that distinction unlike in C++ where function+(a,b) and for
>> (...){} are different.
>
> I don't follow.  I can write a function
>
> 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) 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.

> 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.

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

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.

> Part of the problem is that I really didn't understand
> Mathematica well when I started using things such as Dr. Maeder's  
> Classes
> package.

I have heard a lot about Dr. Maeder's package on this mailing list  
but I have not personally used it or investigated it much.

Regards,

Ssezi

0
mukasa (387)
12/8/2005 5:26:48 AM
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

0
hattons (214)
12/8/2005 5:30:35 AM
On Dec 7, 2005, at 1:43 PM, Steven T. Hatton wrote:

> 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'm not sure what that's supposed to prove we know that of Head 
[{1,2,3}][[0]] is Symbol but Symbol[List] is not a 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.

I believe the point about being arrays of pointers is related to  
implementation efficiency concerns, such as being able to take parts  
of lists in linear time eg:

Block[{a=Table[Random[],{1000}]},
ListPlot[Plus @@@
     Table[Table[Timing[a[[i]]][[1]], {
         i, j}] /. Second -> 1, {j, 100}], PlotJoined -> True];]

Admittedly that is not the purest example but I think it demonstrates  
the point.  For reasoning about the behavior of Mathematica with  
respect to transformation rules though the Head[Arguments...] model  
should be correct even though it will not be correct for predicting  
algorithmic performance.

>> 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

OK calling it syntactic sugar is a bit extreme, it doesn't change the  
validity of the statement.  You cannot create the argument that  
Integer[_] uses to represent an integer, but we know that Integer[_]  
represents an atomic expression so there's no point in wondering  
about what _ is without a head because we cannot create it.  Integer 
[1] is evaluated as Integer[Integer[(something)]] so of course Integer 
[1]/=1.

> In[3]:= Attributes[1]
>
> Attributes::ssle:
>    Symbol, string, or HoldPattern[symbol] expected at position 1 in
>     Attributes[1].
>
> Out[3]= Attributes[1]

Attributes expects a symbol as its argument, Integer[1] or 1 is not a  
symbol so this behavior is not surprising.  On the other hand:

In[18]:=
Attributes[Integer]

Out[18]=
{Protected}

as we'd expect.

>> 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]

I'm not sure what you are expecting in these cases so I'm not really  
sure what the point of this exercise is, at any rate

In[34]:=
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]
Head[25/17]===Denominator[25/17]
Head[E^I GoldenRatio//N]===Re[E^I GoldenRatio//N]
Head[E^I GoldenRatio//N]===Im[E^I GoldenRatio//N]
Head[List]===Symbol

Out[34]=
False

Out[35]=
False

Out[36]=
False

Out[37]=
False

Out[38]=
False

Out[39]=
False

Out[40]=
False

Out[41]=
False

Out[42]=
True

Again as we'd expect.

>> 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.

I agree dealing with the evaluator is subtle, but we have tools for  
dealing with it

In[43]:=
Head[Unevaluated[Subtract[a,b]]]

Out[43]=
Subtract

> See the examples above regarding Integer[1].

To restore clarity, when reasoning about why Head[1] returns Integer  
as a value we have to understand that 1 is an atomic object that can  
be considered to be the expression Integer[1] where the argument is  
actually something I can't create from the Notebook.  Using the  
following as an example:
In[48]:=
Head[1]
1[[0]]
1[[1]]

Out[48]=
Integer

Out[49]=
Integer

 From In[48]:=
"Part specification 1[[ 1 ]] is longer than depth of object.

Out[50]=
1[[1]]

  we begin to understand what makes an expression atomic, it is an  
object of Depth 0.  But objects of Depth 0 still have a head, even  
though the arguments are inaccessible.

> 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.

You have, but I haven't seen an example of behavior that cannot be  
explained by A.9.2.  I will admit that the time complexity of  
algorithms is not what you'd expect from A.9.2 but the behavior with  
respect to types is.

>> 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."

So what's the difficulty?

> C++, however does not have
> a statement type.  It has statements, but "statement" is not a type.

I suppose it depends on your perspective, in order to compile or  
execute C++ code one has to be able to reason about the code and in  
order to reason about the code structures like for(;;){...} and void  
op() have to be represented by something and I'd call that something  
which represents them their type.  Except for the compiler/ 
interpreter though there is nothing within C++ which deals with such  
structures directly, but C++ also has typedef _ structures (and int,  
float, etc.)  which can be used for explicit manipulation of types of  
objects during execution (or evaluation) of a program.  The  
difference between C++, Java etc. and Mathematica (and to a certain  
extent ML, Haskell etc.) is that at evaluation type the structures  
that correspond to for(;;){...}, void op() etc. can be manipulated by  
the program itself.

I'm aware that clever hackers can write self modifying code in C++  
with injudicious use of pointers, but those programs typically rely  
on a well defined external environment of linkers, machine  
architecture etc. to work.

> "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?

There is no need for rtti in Mathematica, again because the type of  
everything is known because there is only one type of thing in  
Mathematica.  A C++ program typically (if we're going to be pedantic  
I'll allow for clever hacks) cannot rewrite its virtual function  
table at run time, during Mathematica evaluation I can rewrite the  
body of a function though.

>   You most certainly can get some
> internal information from an object that way.

I didn't say you couldn't get any information, I said you can't get  
at the implementation.

>> (actually is that a requirement?  http://root.cern.ch/root/
>> Cint.html)
>
> That would not pass muster among 99% of C++ programmers.

I actually posed that question to myself as I was writing then found  
Cint through Google.  I didn't even bother to evaluate it, I was just  
interested in the question of whether being compiled was a necessary  
part of the C or C++ specification.

>> 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.

C++ templates don't modify statements, they are used to generate new  
statements at compile time.  I cannot take a pointer to an if{a}else 
{b} block and change the value of b.

I'm not arguing that is a good idea in general, merely that it isn't  
possible.

>> 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.

And what is something reasonable?  The naive vector3D operator*(a  
vector3D, b vecto3D) {return Vector3D(a.x*b.x,a.y*b.y,a.z*v2.z)}  
requires the creation of an intermediate object in compiling a*b*c to  
hold the result of either a*b or b*c.  Mathematica gets around the  
problem using the Listable attribute, C++ gets around it with  
template metaprogramming (and given your interest in ML perhaps you'd  
appreciate this http://people.cs.uchicago.edu/~jacobm/pubs/ 
templates.html) but as far as I'm aware Java can do neither and ends  
up being inefficient.

>   You can also use composite function objects
> which will blow the doors off of any Mathematica code you can dream  
> up.

We're starting to wander of topic, and I suppose I led us here.  This  
was really just meant as an aside about standard OO programming.

Regards,

Ssezi

0
mukasa (387)
12/8/2005 5:31:21 AM
Sseziwa Mukasa wrote:

> 
> On Dec 7, 2005, at 1:43 PM, Steven T. Hatton wrote:
> 
>> On Wednesday 07 December 2005 10:54, Sseziwa Mukasa wrote:

>>> I meant the value of evaluating the expression.
>>
>> In[1]:= Head[Head[{1,2,3}]]
>>
>> Out[1]= Symbol
> 
> I'm not sure what that's supposed to prove we know that of Head
> [{1,2,3}][[0]] is Symbol but Symbol[List] is not a list.

Well, that makes two of us.  I don't really understand what your example was
intended to demonstrate.  Perhaps you were trying to show that Mathematica
does not behave according to naive expectations in some (many) cases. 
Though I accept the proposition as a forgone conclusion, your example did
not work for me because the result conformed to my expectation.

>> 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.
> 
> I believe the point about being arrays of pointers is related to
> implementation efficiency concerns, such as being able to take parts
> of lists in linear time eg:

Indeed.  This is exactly why iteration is typically faster in C and C++ than
is recursion.  More to the point, it is faster to iterate a pointer value
than it is to dereference a pointer when traversing a linked list.  Fact of
the matter is, when Lisp was originally conceived, such considerations were
still years away from being relevant.  This serves to highlight the dangers
of naively transferring "best practices" from languages such as C++ to
Mathematica.

An aside on Lisp.  I believe that Mathematica expressions are most similar
to Lisp a-lists in terms of how Mathematica compares to Lisp.
>
>>> 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
> 
> OK calling it syntactic sugar is a bit extreme, it doesn't change the
> validity of the statement.  You cannot create the argument that
> Integer[_] uses to represent an integer, but we know that Integer[_]
> represents an atomic expression so there's no point in wondering
> about what _ is without a head because we cannot create it.  Integer
> [1] is evaluated as Integer[Integer[(something)]] so of course Integer
> [1]/=1.

I suspect what we have here is an illdefined "rough edge" of Mathematica's
language "specification".  After having spent some time discussing issues
related to the C++ Standard ISO/IEC 14882:2003, I realize how difficult it
is to specify the details of a programming language, even when the language
was formally specified at every step of its evolution.  It may be virtually
impossible to give an expost facto specification for the Mathematica
programming language.

I believe your intent it to show that all statements in Mathematica are
internally represented in a nested tree structure containing nothing but
arrays of pointers with the first pointer pointing to the head of an
expression and zero or more pointers pointing to the arguments, which are
themselves similarly constructed. I.e., Mathematica is one big glorified
Lukasiewicz (Polish) symbolic calculator.

I agree.  Before I read revelant portions of The Mathematica Book carefully,
I was inclined to call that internal representation "the Mathematica
programming language".  It appears that such a limited view is not the
intent of Dr. Wolfram.  One might even draw a parallel to C++ and assembler
where the generalized input form of Mathematica corresponds to C++ source
code, and internal form corresponds to assembler instructions.

>>> 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]
> 
> I'm not sure what you are expecting in these cases so I'm not really
> sure what the point of this exercise is, at any rate

The point was that Atoms in C++ represent the fundamental units of data
storage.  Each atom is a 'quantum' of data, to use the German manner of
speaking.  The head of an atom is a means of identifying its type, but the
"type" really has to do what "what's in it".  In general, the use of Head
to determin the type of an expression will not provide us this kind of
exact correspondence.  That is to say, knowing that an expression has the
head List does not tell us the nature of what is in the list.  Knowing that
an expression has the head Complex, for example, tells us that we can
extract exactly two meaningful values from it, and how to extract these
values (assuming we know the Mathematica rules for Complex).

> In[48]:=
> Head[1]
> 1[[0]]
> 1[[1]]
> 
> Out[48]=
> Integer
> 
> Out[49]=
> Integer
> 
>  From In[48]:=
> "Part specification 1[[ 1 ]] is longer than depth of object.
> 
> Out[50]=
> 1[[1]]
> 
>   we begin to understand what makes an expression atomic, it is an
> object of Depth 0.  But objects of Depth 0 still have a head, even
> though the arguments are inaccessible.
> 
>> 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.
> 
> You have, but I haven't seen an example of behavior that cannot be
> explained by A.9.2.  I will admit that the time complexity of
> algorithms is not what you'd expect from A.9.2 but the behavior with
> respect to types is.

There are many features which are not well communicated in The Mathematica
Book.  Some of this is probably due to the closed nature of the product,
and some is due to the difficulty in explaining so many subtle interacting
features, and their consequences.
 
>>> 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."
> 
> So what's the difficulty?

Integer[1]===1 for starters.  But I really quoted the statement to affirm my
original position that Mathematica does have a rudementry type system.

>> C++, however does not have
>> a statement type.  It has statements, but "statement" is not a type.
> 
> I suppose it depends on your perspective, in order to compile or
> execute C++ code one has to be able to reason about the code and in
> order to reason about the code structures like for(;;){...} and void
> op() have to be represented by something and I'd call that something
> which represents them their type. 

Perhaps that is valid in a metalinguistic realm, but with C++ there is a
well defined meaning for the term "type" when applied to constructs of the
language.  The distinction between what is meant by "statement" and
"expression" in the ISO/IEC 14482:2003 _Programming languages - C++_ is
akin to the distinction between what is meant by "sentence" and "imperative
sentence".  

> Except for the compiler/ 
> interpreter though there is nothing within C++ which deals with such
> structures directly, but C++ also has typedef _ structures (and int,
> float, etc.)  which can be used for explicit manipulation of types of
> objects during execution (or evaluation) of a program. 

Not really.  These only come into play at compile time.  The only runtime
type-related mechanisms in C++ are virtual functions and RTTI, and these
only apply to a subset of user defined types.

> The 
> difference between C++, Java etc. and Mathematica (and to a certain
> extent ML, Haskell etc.) is that at evaluation type the structures
> that correspond to for(;;){...}, void op() etc. can be manipulated by
> the program itself.

Can I actually modify an expression as it is evaluated?  Let's consider a
For[] expression.  Can you give an example of modifying a For[] expression
as it it evaluated?

> I'm aware that clever hackers can write self modifying code in C++
> with injudicious use of pointers, but those programs typically rely
> on a well defined external environment of linkers, machine
> architecture etc. to work.

I do not consider that to be self-modifying "code".  The runtime image may
be self-modifying, but that is not the same as saying the source code is
modified as the program executes.  To do what Mathematica does in C++ we
would need to create a program that could read its own source code,
manipulate it, invoke a compiler to compile the result, and load the
resulting object code as part of the current execution image.  It is
certainly conceivable, and to some extent it is done with Java today.

>> "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?
> 
> There is no need for rtti in Mathematica, again because the type of
> everything is known because there is only one type of thing in
> Mathematica.

I do not agree with the assertion that there is only one type of thing in
Mathematica.  To say everything is an expression fails to address the
distinct nature of atomic objects with distinct heads.  It is meaningful
and clear to consider atomic objects to have distinct types.

In C++ I can do just about anything I want with RTTI.  The mechanism was
intentionally left openended.  But let's look at a more compelling analog. 
What about Java's facility for introspection?  I Java I can access
extensive details about the structure of an object at runtime.  I will
grant that I cannot (easily) modify the definition of an existing class in
Java.  But I have to ask, how often do we actually modify the original
expression in Mathematica?  Is it not far more common to produce a modified
copy of the original expression?

> A C++ program typically (if we're going to be pedantic 
> I'll allow for clever hacks) cannot rewrite its virtual function
> table at run time, during Mathematica evaluation I can rewrite the
> body of a function though.

Can you provide an example?

>>   You most certainly can get some
>> internal information from an object that way.
> 
> I didn't say you couldn't get any information, I said you can't get
> at the implementation.

It would be far more accurate to say you cannot get at the original
definition.  That is quite true, be cause the definition is part of the
sourcecode, and does not exist in the runtime image.  But that brings us
back to the fact that C++ is compiled and thus the sourcecode is not, in
general, available to the execution image at runtime. 
 
>>> (actually is that a requirement?  http://root.cern.ch/root/
>>> Cint.html)
>>
>> That would not pass muster among 99% of C++ programmers.
> 
> I actually posed that question to myself as I was writing then found
> Cint through Google.  I didn't even bother to evaluate it, I was just
> interested in the question of whether being compiled was a necessary
> part of the C or C++ specification.

All that is required is that the program behave "as if" it were run on the
"abstract machine" specified by the ISO/IEC 14482:2003.

>>> 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.
> 
> C++ templates don't modify statements, they are used to generate new
> statements at compile time. 

C++ templates are used to produce specialization which are modifications of
the original template.  The exact form of these specializations can be
computed at compile time.  This is called template metaprogramming.

> I cannot take a pointer to an if{a}else 
> {b} block and change the value of b.

Allowing for the incorrectness of the notion of taking a pointer to an if
statement, you most *certainly* *can* change the value of b at compile time
in your example.  Template metaprogramming is fairly similar to Mathematica
programming.

> I'm not arguing that is a good idea in general, merely that it isn't
> possible.

But it *is* possible.  It is the whole essence of generic programming.

>>> 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.
> 
> And what is something reasonable?  The naive vector3D operator*(a
> vector3D, b vecto3D) {return Vector3D(a.x*b.x,a.y*b.y,a.z*v2.z)}
> requires the creation of an intermediate object in compiling a*b*c to
> hold the result of either a*b or b*c.  Mathematica gets around the
> problem using the Listable attribute, C++ gets around it with
> template metaprogramming

Or compiler optimizations, or composite function objects, valarrays, etc.  I
will grant that I like the way Mathematica handles such situations, and
have as an objective finding ways to formalize such techniques in C++.

> (and given your interest in ML perhaps you'd 
> appreciate this http://people.cs.uchicago.edu/~jacobm/pubs/
> templates.html) but as far as I'm aware Java can do neither and ends
> up being inefficient.

I'd better stick with Mathematica for now.  I took a very sharp turn by
dropping C++ after 18 months of careful study and returning to Mathematica. 
I obviously am interested in how programming languages work, and how
Mathematica works as a programming language in the purely academic sense. 
But, believe it or not, my primary motivation for spending so much time and
effort on this topic is because I was tired of trying to use Mathematica,
and not getting the results I expected.

This discussion has forced me to examine how I perceive Mathematica, and how
accurate those perceptions are.
-- 
The Mathematica Wiki: http://www.mathematica-users.org/
Math for Comp Sci http://www.ifi.unizh.ch/math/bmwcs/master.html
Math for the WWW: http://www.w3.org/Math/

0
hattons (214)
12/9/2005 10:28:16 AM
On Thursday 08 December 2005 11:48, Sseziwa Mukasa wrote:
I hope it's OK that I put this back into mathgroup.  It doesn't seem to 
contain anything of a personal nature, nor anything else inappropriate for 
the list.

> On Dec 8, 2005, at 9:42 AM, Steven T. Hatton wrote:
[...]

Looks as if we've both lost the original point we were debating.

> I'm not really concerned with what the machine representation of
> Mathematica's structures are internally, I'm interested in a
> representation that allows me to reason about programs correctly.

I find it to often be the case that an understanding of internal 
representation is helpful in reasoning about how to use the language.  It 
certainly helps me contemplate expressions in Mathematica to understand them 
as trees of pointers whose leaves are atoms.

> Similarly were I using a LISP machine as my processor but writing
> programs in C that are passed through a compiler written in LISP I
> would be similarly uninterested in how the compiler represented C
> structures, or what the machine native structures of the compiler
> program looked like, as long as it behaved in a manner conforming to
> the C specification.

I will take that as in indication that you do not have a lot of C++ 
experience.  Before I really focused on C++ I would have said the same thing.  
Now I realize that C++ requires a certain amount of understanding at the 
machine level.

> > One might even draw a parallel to C++ and assembler
> > where the generalized input form of Mathematica corresponds to C++
> > source
> > code, and internal form corresponds to assembler instructions.
>
> Agreed, I think where we'd disagree is in the importance of the
> mapping of C++ source code to assembly.

I've never spent much time looking at the assembly code produced by compiling 
C++, but there are certainly times when understanding how the sourcecode is 
represented in the compiled result helps to solve problems and/or increase 
efficiency.  As far as understanding the STL, I see no way to gain more than 
a vague notion of how it works without understanding the runtime structure of 
the realized collections.

> > The point was that Atoms in C++ represent the fundamental units of
> > data
> > storage.
>
> C++ has atoms?  This is a genuine question prompted by laziness in
> not wanting to read through a specification document to find out.

Sorry, that was my mistake.  I meant to say Mathematica Atoms.

> > The head of an atom is a means of identifying its type, but the
> > "type" really has to do what "what's in it".
>
> Doesn't what's in it have to do with the physical machine, I believe
> that Intel CPUs internally use some form of 80 bit floating point
> format which is converted back and forth to 64 bit constructs when
> doing double precision calculations.  When you execute a program on
> an actual machine then what's in it is really an 80 bit value,
> regardless of what the head says.

But a Complex will always have a real and an imaginary component.  A Rational 
will always have a numerator and a denominator.  I didn't intend the actual 
physical representation of the atom in memory.  It really doesn't matter if, 
say, complex were stored as an angle and a magnitude, or or as a real part 
and an imaginary part, so long as I could recover the real and imaginary 
parts.  The point is that knowing that an atom has head Complex tells me what 
kind of thing it is at the user level.

> > That is to say, knowing that an expression has the
> > head List does not tell us the nature of what is in the list.
>
> I know what's in a list, zero or more expressions.  I can ask if the
> expressions are atomic and if it is important I can assign types to
> the atoms by their heads.  In fact it's not even necessary that they
> be atoms because I can still unambiguously assign a type.

I'm not sure it's meaningful/useful to assign a type to an atom beyond what is 
already implied.

> >   Knowing that
> > an expression has the head Complex, for example, tells us that we can
> > extract exactly two meaningful values from it, and how to extract
> > these
> > values (assuming we know the Mathematica rules for Complex).
>
> Actually you don't know the types of the values from the head Complex
> beyond that they belong to the Numeric class anymore than you know
> the types of the elements of a List, if there are any, beyond that
> they are of the class expression.
>
> In[117]:=
> Head[5+6. I]
> Head[Re[5+6. I]]
> Head[Im[5+6. I]]
>
> Out[117]=
> Complex
>
> Out[118]=
> Integer
>
> Out[119]=
> Real

Certainly a valid observation worth considering when using Complex numbers.  
Even more surprizing to the uninitiated might be Head[Arg[1+I]].

> >> So what's the difficulty?
> >
> > Integer[1]===1 for starters.  But I really quoted the statement to
> > affirm my
> > original position that Mathematica does have a rudementry type system.
>
> I still fail to see the problem Integer[1] is of the form Integer
> [Integer[(something that's not very important)]] and 1 is of the form
> Integer[(something that's not very important except that it behaves
> as 1, whatever that is)].

But that is something learned from experience, not from reading A.9.2

> My larger point, which is yet another diversion from the point of the
> thread was that because there is only one type of thing in
> Mathematica and it is the same thing that the evaluator uses as what
> the user reasons about then the ability to write self modifying code
> in Mathematica itself is a necessary consequence.  I didn't suggest
> this was a good idea, merely that it was a hint as to the nature of
> type in Mathematica.

There are cases when one benefits by adding downvalues to a symbol during 
evaluation.  The canonical example is "functions that remember values" in 
recursive algorithms.

> > I do not agree with the assertion that there is only one type of
> > thing in
> > Mathematica.  To say everything is an expression fails to address the
> > distinct nature of atomic objects with distinct heads.  It is
> > meaningful
> > and clear to consider atomic objects to have distinct types.
>
> To me it depends on your point of view.  Viewed as system of rewrite
> rules, there are only two things which compose Mathematica:
> expressions of form Head[Argument....] and transformation rules which
> map one value of Head[Argument...] onto another.

I am coming to realize there is another dimension worth considering when 
trying to identify the essential abstract nature of Mathematica.  We have 
expressions which have a head and zero or more "arguments", and we have 
symbols capable of holding transformation rules applicable to the symbol.  
The four types of values that I know of which can be associated with a symbol 
are UpValues, OwnValues, DownValues, and SubValues, all of which are 
expressions of one form or another.  The behavior of Mathematica seems to be 
the Cartesian product of the value dimension, if you will, and the expression 
dimension.



Steven

0
hattons (214)
12/9/2005 10:38:51 AM
On Dec 8, 2005, at 2:19 PM, Steven T. Hatton wrote:

> On Thursday 08 December 2005 11:48, Sseziwa Mukasa wrote:
> I hope it's OK that I put this back into mathgroup.  It doesn't  
> seem to
> contain anything of a personal nature, nor anything else  
> inappropriate for
> the list.

At some point it looks like the list got dropped from recipients.  I  
wonder how many stalwarts are still along on this journey anyway.

>> On Dec 8, 2005, at 9:42 AM, Steven T. Hatton wrote:
> [...]
>
> Looks as if we've both lost the original point we were debating.

True

> I will take that as in indication that you do not have a lot of C++
> experience.

I have not done any major programming in C++, but I did do some C++  
coding predating the STL.  Incidentally Mathematica is not my primary  
programming environment; which is much closer to C++ than Mathematica  
in spirit.

> As far as understanding the STL, I see no way to gain more than
> a vague notion of how it works without understanding the runtime  
> structure of
> the realized collections.

But of what use is that knowledge when compared to similar facilities  
in other languages (Java Collections, Ada Generics (or rather Ada  
libraries using Ada Generics), etc)?  In my opinion it's better to  
understand the model than the implementation.  And yes, I'm aware  
that Java Collections and Ada Generics do not map directly to the  
STL, but the STL is a particular implementation of a more general  
idea of which collections and generics are also a part.

> But a Complex will always have a real and an imaginary component.   
> A Rational
> will always have a numerator and a denominator.

And a List always contains zero or more expressions.

> The point is that knowing that an atom has head Complex tells me what
> kind of thing it is at the user level.

I guess I don't understand why this is any different from things with  
head List.

> I'm not sure it's meaningful/useful to assign a type to an atom  
> beyond what is
> already implied.

I meant that I can assign a type to things that aren't atoms like  
Integer[1] or {1,2,3}.

> Certainly a valid observation worth considering when using Complex  
> numbers.
> Even more surprizing to the uninitiated might be Head[Arg[1+I]].

I still consider cases like this to be artifacts of the evaluator.   
That the evaluator rewrites the expression for Arg[1+I] doesn't make  
its head surprising.

> I am coming to realize there is another dimension worth considering  
> when
> trying to identify the essential abstract nature of Mathematica.   
> We have
> expressions which have a head and zero or more "arguments", and we  
> have
> symbols capable of holding transformation rules applicable to the  
> symbol.

I prefer to think of the rewrite rules as just being given in the  
same way as axioms are just given, symbols aren't necessary.   
Similarly creating new rules can be thought of as stating theorems  
(but significantly not proving them) and they just get added to the  
preexisting axioms.  This analogy is unintentionally wandering a  
little to close to some of the New Kind of Science ideas but it was  
the first that came to mind.

> The four types of values that I know of which can be associated  
> with a symbol
> are UpValues, OwnValues, DownValues, and SubValues, all of which are
> expressions of one form or another.  The behavior of Mathematica  
> seems to be
> the Cartesian product of the value dimension, if you will, and the  
> expression
> dimension.

Or perhaps a breadth first search along a kind of tree structure (or  
perhaps it's more properly a directed graph) formed by this product.

Regards,

Ssezi

0
mukasa (387)
12/9/2005 10:39:37 AM
Sseziwa Mukasa wrote:

> 
> On Dec 8, 2005, at 2:19 PM, Steven T. Hatton wrote:
[...]
> But of what use is that knowledge when compared to similar facilities
> in other languages (Java Collections, Ada Generics (or rather Ada
> libraries using Ada Generics), etc)?  In my opinion it's better to
> understand the model than the implementation.  And yes, I'm aware
> that Java Collections and Ada Generics do not map directly to the
> STL, but the STL is a particular implementation of a more general
> idea of which collections and generics are also a part.

In Java you don't need to have a very deep understanding of the runtime
structure for most purposes.  But then again, Java is not a high
performance language - regardless of silliness you will find comparing
"C++" "malloc" to Java.  Such blather is exceptionally silly when one stops
to consider that Java is implemented in C and C++.  I don't want to go too
far off topic, so just let me say, C++ was designed to be, and is "close to
the metal".  If you don't understand the runtime structure of STL
collections, you will eventually shoot yourself in the foot.  Something
will move out from under your reference, and you will find yourself
accessing something you have no business accessing. 

>> But a Complex will always have a real and an imaginary component.
>> A Rational
>> will always have a numerator and a denominator.
> 
> And a List always contains zero or more expressions.

I don't see that to be containment in the same sense as a Complex contains
its values.  I don't know about the physical implementation, but it seems
more meaningful to compare the value returned by Length[list] to the data
held in an expression/symbol with the head Complex.  Even if we do view an
expression with the head List as a data structure containing elements
(often called arguments), we are still able to describe it in terms of the
functions which can operate on it, as well as the data abstraction it
represents.

When using expressions to represent ADTs we usually don't want to simply
extract values using Part.  We want to treat it as if we do not know the
internal structure.  We only know the interface.

>> The point is that knowing that an atom has head Complex tells me what
>> kind of thing it is at the user level.
> 
> I guess I don't understand why this is any different from things with
> head List.

You cannot extract the components of an expression with head Complex using
Part[].  You have to "ask nicely".  For Lists, I believe that Part[] /is/
"asking nicely".
 
>> I'm not sure it's meaningful/useful to assign a type to an atom
>> beyond what is
>> already implied.
> 
> I meant that I can assign a type to things that aren't atoms like
> Integer[1] or {1,2,3}.

Conceptually, perhaps, but when I talk about assigning a type in this
context, I usually mean making an actual assignment (declaration). 

I just found this and have only glanced at it, but I believe it will give a
good context for further discussion on this matter:

http://library.wolfram.com/infocenter/Conferences/4680/

>> Certainly a valid observation worth considering when using Complex
>> numbers.
>> Even more surprizing to the uninitiated might be Head[Arg[1+I]].
> 
> I still consider cases like this to be artifacts of the evaluator.
> That the evaluator rewrites the expression for Arg[1+I] doesn't make
> its head surprising.

What determines (holds) the value of Arg[1+I]?  Where does it "live"?

>> I am coming to realize there is another dimension worth considering
>> when
>> trying to identify the essential abstract nature of Mathematica.
>> We have
>> expressions which have a head and zero or more "arguments", and we
>> have
>> symbols capable of holding transformation rules applicable to the
>> symbol.
> 
> I prefer to think of the rewrite rules as just being given in the
> same way as axioms are just given, symbols aren't necessary.
> Similarly creating new rules can be thought of as stating theorems
> (but significantly not proving them) and they just get added to the
> preexisting axioms.  This analogy is unintentionally wandering a
> little to close to some of the New Kind of Science ideas but it was
> the first that came to mind.

I don't know about the analogy of axioms, but I certainly agree that they
are simply put there.

You might find this interesting:
http://www.nomic.net/~nomicwiki/index.php/GameOfNomic

My point in talking about multiple dimensions is to try to categorize the
kinds of stuff that can be associated (attached to) a symbol.  These might
be viewed similarly to how domains in relational databases are viewed. 

Values seem to from a 2D axis with axis representing OwnValues at the origin
between UpValues and DownValues (though OwnValues seem to take precedence
over UpValues,) and SubValues describing an axis orthogonal to the first.
UpValues
DownValues
OwnValues
SubValues

Arguments (elements)
Dr. Mader describes options as named arguments (implying order
independence).
Options

Head
Attributes
internal data
messages

Context (symbol is probably best understood as a fully qualified name.)


>> The four types of values that I know of which can be associated
>> with a symbol
>> are UpValues, OwnValues, DownValues, and SubValues, all of which are
>> expressions of one form or another.  The behavior of Mathematica
>> seems to be
>> the Cartesian product of the value dimension, if you will, and the
>> expression
>> dimension.
> 
> Or perhaps a breadth first search along a kind of tree structure (or
> perhaps it's more properly a directed graph) formed by this product.

Expressions certainly have a tree structure in as much as the part
specifications can be viewed as addresses into a tree.  It does seem that a
symbol can appear multiple times in this tree.  I'm not sure if the
evaluator will jump from one subtree to another without following a strict
traversal.  It seems to be rewriting the expression tree as it evaluates
it, but does it ever jump to a location that is not an ancestor or
descendent of the current location?

-- 
The Mathematica Wiki: http://www.mathematica-users.org/
Math for Comp Sci http://www.ifi.unizh.ch/math/bmwcs/master.html
Math for the WWW: http://www.w3.org/Math/

0
hattons (214)
12/10/2005 11:12:00 AM
On Dec 9, 2005, at 10:48 AM, Steven T. Hatton wrote:

>
> Sseziwa Mukasa wrote:
>>> But a Complex will always have a real and an imaginary component.
>>> A Rational
>>> will always have a numerator and a denominator.
>>
>> And a List always contains zero or more expressions.
>
> I don't see that to be containment in the same sense as a Complex  
> contains
> its values.

You're right it's not exactly the same because Complex is an atom and  
a list is not.

> expression/symbol with the head Complex.

Only an expression can have the head Complex, a symbol has the head  
Symbol and to prevent confusion I think we should agree to keep that  
straight.

>   Even if we do view an
> expression with the head List as a data structure containing elements
> (often called arguments), we are still able to describe it in terms  
> of the
> functions which can operate on it, as well as the data abstraction it
> represents.

Of which the abstraction is what?

> When using expressions to represent ADTs we usually don't want to  
> simply
> extract values using Part.  We want to treat it as if we do not  
> know the
> internal structure.  We only know the interface.

I don't think I agree with this, we know several things about Part  
with respect to expressions: Part cannot take anything beyond the 0th  
(head) element of atoms, Part returns a Message when the index is  
greater than the depth of the expression being taken apart, Part  
returns the expression corresponding to an argument of the larger  
expression when 0 < the second argument to part <= Depth[first  
argument].  If you consider the arguments to be internal structure  
then the behavior of Part makes it necessary that you treat  
expressions as if you know something about their internals.  It also  
makes clear what an atom is: a Depth 0 object.

> You cannot extract the components of an expression with head  
> Complex using
> Part[].

Because by definition you cannot do that to any atom and an  
expression of the form Complex[_,_] is an atom.

>   You have to "ask nicely".  For Lists, I believe that Part[] /is/
> "asking nicely".

I don't consider this exceptional, all you have to do is distinguish  
the behavior of Part between things that are atoms and things that  
are not, all the rest follows logically.

> I just found this and have only glanced at it, but I believe it  
> will give a
> good context for further discussion on this matter:
>
> http://library.wolfram.com/infocenter/Conferences/4680/

Thank you for the pointer, I'll read it.

> What determines (holds) the value of Arg[1+I]?

The value of Arg[1+I] is Arg[1+I] there are also rewrite rules for  
equivalent expressions where equivalence is defined by expr1==expr2  
being congruent to True eg:

In[54]:=
FullForm[Arg[1 + I]]
Arg[1 + I] == Times[1/4, Pi]

Out[54]//FullForm=
Times[Rational[1,4],Pi]

Out[55]=
True.

>   Where does it "live"?

In the space of arguments to the evaluator.  Since there are rewrite  
rules associated with Arg one has to be careful about when they look  
at an Arg expression depending on what they want to do with it.   
Since all the rewrite expressions for Arg have the same value with  
respect to N[Arg[_]] then if one is concerned with the value the head  
is irrelevant, when one is interested in the Head though a Hold or  
Unevaluated must be used to prevent the expression from being rewritten.

> You might find this interesting:
> http://www.nomic.net/~nomicwiki/index.php/GameOfNomic

I've run across it but it's been a while since I read Hofstader,  
thanks for the link.

> My point in talking about multiple dimensions is to try to  
> categorize the
> kinds of stuff that can be associated (attached to) a symbol.   
> These might
> be viewed similarly to how domains in relational databases are viewed.

There are actually some very interesting theoretical on relations and  
how then end up being implemented in RDBMSes (short version,  
poorly).  While we continue on our tour of programming languages the  
logic languages would be appropriate examples for reasoning about  
relations.  And they too bear a strong relationship (pun not  
intended) to LISP like languages.

> UpValues
> DownValues
> OwnValues
> SubValues

These things are side effects of the evaluator, like In and Out, not  
fundamental.  They are very useful though because they describe  
expressions we can use to interact with the rewrite rules used by the  
evaluator itself.

> Arguments (elements)
> Dr. Mader describes options as named arguments (implying order
> independence).
> Options
>
> Head
> Attributes

Attributes are definitely an interesting beast, I'm not sure but I  
suspect they can be considered a special set of rules used by the  
evaluator.

> internal data

I'm not sure internal data is any more worth worrying about to a  
Mathematica programmer as a naked quark is to a nuclear engineer.

> messages

Message are just expressions, which is why you can trace on Message 
[___] to stop evaluation at a point a message is issued.  Messages  
are not atomic.

> Context (symbol is probably best understood as a fully qualified  
> name.)

Likewise a Context is just another expression whose value is a side  
effect of the evaluator (in particular of Get[] and Needs[]  
expressions).  To reason about these things is to reason about the  
rewrite rules of the evaluator, but is aside from the idea of types.

Regards,

Ssezi

0
mukasa (387)
12/10/2005 11:12:48 AM
Sseziwa Mukasa wrote:

> 
> On Dec 9, 2005, at 10:48 AM, Steven T. Hatton wrote:
> 
>>
>> Sseziwa Mukasa wrote:
>>>> But a Complex will always have a real and an imaginary component.
>>>> A Rational
>>>> will always have a numerator and a denominator.
>>>
>>> And a List always contains zero or more expressions.
>>
>> I don't see that to be containment in the same sense as a Complex
>> contains
>> its values.
> 
> You're right it's not exactly the same because Complex is an atom and
> a list is not.

Atoms really do seem to satisfy the definition of abstract data type.  One
might even say they satisfy the definition of object in the OOP sense.

>> expression/symbol with the head Complex.
> 
> Only an expression can have the head Complex, a symbol has the head
> Symbol and to prevent confusion I think we should agree to keep that
> straight.

I stand corrected.  Thanks for pointing that out.  You have inspired me to
attempt a UML class diagram of Mathematica data types.  It will indeed be
rooted with expression.  The problem with that model is that we never have
a thing we refer to as "Expression" within the language.

>>   Even if we do view an
>> expression with the head List as a data structure containing elements
>> (often called arguments), we are still able to describe it in terms
>> of the
>> functions which can operate on it, as well as the data abstraction it
>> represents.
> 
> Of which the abstraction is what?

Well, do you _need_ to know the details of how it is implemented in order to
use it?  List is kind of like a "brown paper wrapper" expression.  Its head
is a Symbol named "List" which has certain attributes. Beyond that,
whatever else it does seems to be determined by what it "inherits" from
"Expression".  I'll have more to say on this soon...I hope.

>> When using expressions to represent ADTs we usually don't want to
>> simply
>> extract values using Part.  We want to treat it as if we do not
>> know the
>> internal structure.  We only know the interface.
> 
> I don't think I agree with this, we know several things about Part
> with respect to expressions:

That's not the point.  I'm talking about a protocol based on mutual
agreement, not a law enforced by software (though there are ways of hiding
internal structure of an ADT - or so Maeder claims.)  This is similar to
the way SIMULA originally handled data abstraction.  It's as if we
implemented our C++ classes as struct with all public data members, and
simply agreed to only use the member functions to access the internal
structure.  In principle you /could/ access the member data, but that would
violate the design principle.

> Part cannot take anything beyond the 0th 
> (head) element of atoms, Part returns a Message

I'm not sure I would use the term "Message" here.  But then, "message" is
something I consider specific to SmallTalk, and not generally useful when
discussing OOP.

> when the index is 
> greater than the depth of the expression being taken apart, Part
> returns the expression corresponding to an argument of the larger
> expression when 0 < the second argument to part <= Depth[first
> argument].  If you consider the arguments to be internal structure 
> then the behavior of Part makes it necessary that you treat
> expressions as if you know something about their internals.  It also
> makes clear what an atom is: a Depth 0 object.

What you are describing is the interface to Expression.  I'm talking about
creating things as composite expressions and treating them _as if_ they
were atomic.

>> You cannot extract the components of an expression with head
>> Complex using
>> Part[].
> 
> Because by definition you cannot do that to any atom and an
> expression of the form Complex[_,_] is an atom.
> 
>>   You have to "ask nicely".  For Lists, I believe that Part[] /is/
>> "asking nicely".
> 
> I don't consider this exceptional, all you have to do is distinguish
> the behavior of Part between things that are atoms and things that
> are not, all the rest follows logically.

The point I'm trying to make is that Atoms are staticly defined data types. 
In reality, they are considered constants.  You cannot change the value
of/in an Atom.  You can only replace the whole Atom.  With an Expression,
you /can/ change its contents. 

>> I just found this and have only glanced at it, but I believe it
>> will give a
>> good context for further discussion on this matter:
>>
>> http://library.wolfram.com/infocenter/Conferences/4680/
> 
> Thank you for the pointer, I'll read it.

I did read it quickley.  It appears Maeder would have had a stronger type
system in Mathematica.  This is what I was really trying to get at when I
started this thread ... back in the Early Modern Era.  I suspect there were
discussion about this sort of thing in the early days, and the notion of a
type system along the lines of C++ was rejected.  Was it just a question of
who could yell loudest or pout longest, or were there solid reasons for not
taking that approach?

What would happen if users could define Atom-like types?  That is, types
that only expose their content through an interface.  Whoops!  That's OOP! 
One of the bigest problems, as I see it, is the lack of automatic type
conversion.

>> What determines (holds) the value of Arg[1+I]?
> 
> The value of Arg[1+I] is Arg[1+I] 

Are you talking about the pattern, or the result given by evaluating the
expression?

> there are also rewrite rules for 
> equivalent expressions where equivalence is defined by expr1==expr2
> being congruent to True eg:
> 
> In[54]:=
> FullForm[Arg[1 + I]]
> Arg[1 + I] == Times[1/4, Pi]
> 
> Out[54]//FullForm=
> Times[Rational[1,4],Pi]
> 
> Out[55]=
> True.

Indeed, another pit of vipers I seem to have stepped into.  What I should
have written was What determines (holds) the value of Arg[1+I]//N?

>>   Where does it "live"?
> 
> In the space of arguments to the evaluator.  Since there are rewrite
> rules associated with Arg one has to be careful about when they look
> at an Arg expression depending on what they want to do with it.

This is certainly a point of frustration I have with Mathematica.  If I look
at the documentation for Arg[], I am not given a comprehensive description
of its behavior.
 
> There are actually some very interesting theoretical on relations and
> how then end up being implemented in RDBMSes (short version,
> poorly).

Not sure exactly what you mean here.  If you are talking about RDBMS vs. say
ODBMS, I haven't seen much come out of ODBMS which I found useful.  The
idea is attractive, but the reality becomes quite a mess.  I really wasn't
suggesting we could, or should, try to describe Mathematica "things" as
entries in an RDBMS, I would merely using the example in order to motivate
the analogy of an axis.

> While we continue on our tour of programming languages the 
> logic languages 

??  What do you mean here?  Can you provide an example?  I have been
glancing at SML over the past few days.  I also compiled and crashed Axiom.

> would be appropriate examples for reasoning about 
> relations.  And they too bear a strong relationship (pun not
> intended) to LISP like languages.

I suspect most languages that strive to capture the essence of mathematical
reasoning will be expressed in a prefix functional form similar to
Mathematica's internal form.  It may not be easy to read or write
expressions in that form, but it makes writting the evaluator much simpler. 
Since Lisp already works this way (moving the head inside the '(',')'), the
will have similarities to Lisp.

>> UpValues
>> DownValues
>> OwnValues
>> SubValues
> 
> These things are side effects of the evaluator, like In and Out, not
> fundamental.  They are very useful though because they describe
> expressions we can use to interact with the rewrite rules used by the
> evaluator itself.

They _are_ the rewrite rules.  At least from the user's perspective.  Do you
not agree?  See 2.6.2 in the Help Browser.

> Attributes are definitely an interesting beast, I'm not sure but I
> suspect they can be considered a special set of rules used by the
> evaluator.

I am willing to bet they are simply bits in a single int variable in the
Symbol struct.  What the consequences of their being there are, is a
different story.  They may well be arguments to a switch statement.

>> internal data
> 
> I'm not sure internal data is any more worth worrying about to a
> Mathematica programmer as a naked quark is to a nuclear engineer.

You may not be interested in the details, but knowing that there is data in
there, and what kind of data abstraction it represents, is certainly
useful.

>> messages
> 
> Message are just expressions, which is why you can trace on Message
> [___] to stop evaluation at a point a message is issued.  Messages
> are not atomic.

It appears there is actually an Expression "Messages" associated with a
Symbol that has messages, so it might be meaningful to view them as member
data of the Symbol.  The are certainly not accessed using a part
specification.

>> Context (symbol is probably best understood as a fully qualified
>> name.)
> 
> Likewise a Context is just another expression whose value is a side
> effect of the evaluator (in particular of Get[] and Needs[]
> expressions). 

Contexts are Strings Head[Context[Arg]]. That's why they need to be quoted
when given as arguments to expressions.

> To reason about these things is to reason about the 
> rewrite rules of the evaluator, but is aside from the idea of types.

I don't agree.  The items I listed are the abstract data members of the
"type" Symbol.  The evaluator doesn't have rewrite rules any more than a
compiler has function definitions.  The rules exist in the expression
structure passed to the evaluator.
-- 
The Mathematica Wiki: http://www.mathematica-users.org/
Math for Comp Sci http://www.ifi.unizh.ch/math/bmwcs/master.html
Math for the WWW: http://www.w3.org/Math/

0
hattons (214)
12/11/2005 10:09:36 AM
On Dec 10, 2005, at 9:38 AM, Steven T. Hatton wrote:

> Atoms really do seem to satisfy the definition of abstract data type.  
> One
> might even say they satisfy the definition of object in the OOP sense.

Sort of, they are a decent candidate.

>> Part cannot take anything beyond the 0th
>> (head) element of atoms, Part returns a Message
>
> I'm not sure I would use the term "Message" here.  But then, "message" 
> is
> something I consider specific to SmallTalk, and not generally useful 
> when
> discussing OOP.

I meant message in the sense of Message[Arguments], from now on when 
talking about Mathematica expressions I'll capitalize the first letter 
and use lower case when some other meaning is intended.  Rereading 
these messages though, I notice that I'm a poor editor of emails so 
there will be mistakes.

> I'm talking about
> creating things as composite expressions and treating them _as if_ they
> were atomic.

Perhaps doing this in pursuit of a specific application would be 
helpful.  I've notices the occasional relativist (the physics type not 
the philosophic type) who is looking to use Mathematica to represent 
tensors and the other structures they work with symbolically.  I 
believe there is a package that does so already, but if there is a 
candidate for something that should act like and Atom but is not one I 
suppose that's it.  I know far too little of what researchers in 
relativity do to be able to pursue that idea further.

> It appears Maeder would have had a stronger type
> system in Mathematica.  [deleted]  I suspect there were
> discussion about this sort of thing in the early days, and the notion 
> of a
> type system along the lines of C++ was rejected.

Many modern languages have rejected the type system used by the various 
C and Algol derived languages: Haskell, ML, Mercury, Prolog, Dylan, 
Common Lisp...  I know a lot of people are happy with C++ but as far as 
I can tell from programming language designers it is not really an 
interesting path to follow.

>   Was it just a question of who could yell loudest or pout longest, or 
> were there solid reasons for not taking that approach?

I suggest reading up on Hindley-Milner type systems, they seem to be 
the rage in statically typed functional languages.

> What would happen if users could define Atom-like types?  That is, 
> types
> that only expose their content through an interface.  Whoops!  That's 
> OOP!

There's nothing inherently wrong with OOP but it achieved prominence on 
the back of C and Algol like languages and those implementations of OOP 
systems create issues that other languages simply don't have.  For 
example at least one person 
(http://norvig.com/design-patterns/ppframe.htm) thinks the Gang of Four 
would not be earning a dime of royalty or consulting fees if they used 
a dynamically typed language because most of their patters are trivial 
in other idioms.

>> The value of Arg[1+I] is Arg[1+I]
>
> Are you talking about the pattern, or the result given by evaluating 
> the
> expression?

Both since an equation is a tautology.  A better way at looking at 
values in a rewrite system though is a value is what happens when there 
are no more rewrite rules left after applying them to the initial 
expression in which case the value in Mathematica is 
Times[Rational[1,4],Pi].

Similarly the value of Unevaluated[Arg[1+I]] is Arg[1+I] since you have 
to submit the argument of Unevaluated to the evaluator again.

> Indeed, another pit of vipers I seem to have stepped into.  What I 
> should
> have written was What determines (holds) the value of Arg[1+I]//N?

What determines the value is the evaluator, what holds it is some 
expression, in this case one with the head Real.

>> Since there are rewrite
>> rules associated with Arg one has to be careful about when they look
>> at an Arg expression depending on what they want to do with it.
>
> This is certainly a point of frustration I have with Mathematica.  If 
> I look
> at the documentation for Arg[], I am not given a comprehensive 
> description
> of its behavior.

A large part of the Mathematica Book is dedicated to describing the 
evaluator, it would be redundant to repeat it every time.

>> While we continue on our tour of programming languages the
>> logic languages
>
> ??  What do you mean here?  Can you provide an example?  I have been
> glancing at SML over the past few days.  I also compiled and crashed 
> Axiom.

I was thinking of languages similar to Prolog, but this is aside from 
the topic of this thread.

>>> UpValues
>>> DownValues
>>> OwnValues
>>> SubValues
>>
>> These things are side effects of the evaluator, like In and Out, not
>> fundamental.  They are very useful though because they describe
>> expressions we can use to interact with the rewrite rules used by the
>> evaluator itself.
>
> They _are_ the rewrite rules.  At least from the user's perspective.  
> Do you
> not agree?  See 2.6.2 in the Help Browser.

I agree that that is what they are, and their existence makes it 
possible to write self modifying code pretty easily should the need 
arise.  But they are not necessary.

>> Attributes are definitely an interesting beast, I'm not sure but I
>> suspect they can be considered a special set of rules used by the
>> evaluator.
>
> I am willing to bet they are simply bits in a single int variable in 
> the
> Symbol struct.  What the consequences of their being there are, is a
> different story.  They may well be arguments to a switch statement.

Again we're thinking on different levels, I'm not really interested in 
what the implementation of Mathematica looks like (I understand it's a 
blend of C and Mathematica itself).  I'm interested in how one would 
model the evaluator in the abstract.

In my job our product is a blend of an interpreted language and an 
internal implementation in another language and I can honestly say that 
there would be no enlightenment for someone seeking to understand the 
interpreted language to look at its implementation.

> I don't agree.  The items I listed are the abstract data members of the
> "type" Symbol.  The evaluator doesn't have rewrite rules any more than 
> a
> compiler has function definitions.  The rules exist in the expression
> structure passed to the evaluator.

Regardless of how the evaluator actually works, the question is how you 
can reason about it accurately with respect to generating the correct 
output for a given input (even if you get the algorithmic complexity 
wrong).  I submit that the correct way to think about it is as a 
rewrite system, as others have said.

Regards,

Ssezi

0
mukasa (387)
12/11/2005 10:27:23 AM
On Saturday 10 December 2005 20:10, Sseziwa Mukasa wrote:
> On Dec 10, 2005, at 9:38 AM, Steven T. Hatton wrote:

> I meant message in the sense of Message[Arguments], from now on when
> talking about Mathematica expressions I'll capitalize the first letter
> and use lower case when some other meaning is intended.  Rereading
> these messages though, I notice that I'm a poor editor of emails so
> there will be mistakes.
Oh, now I see what you meant.  Part[Complex, 1].  To be pedantic, it doesn't 
actually "return" the Message.  It displays it, and returns  
Complex\[LeftDoubleBracket]1\[RightDoubleBracket].

> > I'm talking about
> > creating things as composite expressions and treating them _as if_ they
> > were atomic.
>
> Perhaps doing this in pursuit of a specific application would be
> helpful.  I've notices the occasional relativist (the physics type not
> the philosophic type) who is looking to use Mathematica to represent
> tensors and the other structures they work with symbolically.  I
> believe there is a package that does so already, but if there is a
> candidate for something that should act like and Atom but is not one I
> suppose that's it.  I know far too little of what researchers in
> relativity do to be able to pursue that idea further.

That is actually one of my primary interests.  Interestingly, I have 
discovered the formulae describing hurricanes look a whole lot like those in 
general relativity.  That was the impetus for my returning to Mathematica. 

WRT tensor packages, the moderator of this newsgroup created a commercial 
package called MathTensor.  It's pricy. At least for my current situation.  
I'm not sure why the Unix version (I assume that includes Linux) costs $230 
more than the $570 price for the Mac and Windows versions.  When I feel 
confident with my Mathematica skills, I may consider buying it.

I don't expect it to be OOP based.

> Many modern languages have rejected the type system used by the various
> C and Algol derived languages: Haskell, ML, Mercury, Prolog, Dylan,
> Common Lisp...  I know a lot of people are happy with C++ but as far as
> I can tell from programming language designers it is not really an
> interesting path to follow.

It's also a hard act to follow.  D is the closest thing I know of to a serious 
effort to improve on the C++ principles.  You can find more here:
http://digitalmars.com/d/comparison.html

C++ has some problems.  Many of them have to do with the fact that it strives 
to be C compatable.  One thing I've learned from studying C++ is that the 
builtin features of other languages can usually be implemented or emulated in 
C++.  In many respects, it's good that C++ hasn't incorporated every 
newfangled idea that's come along.  It really is intended to be a basis for 
building complete development systems, and not such a system.  IMO, one of 
the biggest problems of C++ is the fact that too many people treat it like C.

> >   Was it just a question of who could yell loudest or pout longest, or
> > were there solid reasons for not taking that approach?
>
> I suggest reading up on Hindley-Milner type systems, they seem to be
> the rage in statically typed functional languages.

It would seem a likely candidate for Mathematica. I don't know if you were 
suggesting a reason why there isn't a comprehensive type system in 
Mathematica.

> > What would happen if users could define Atom-like types?  That is,
> > types
> > that only expose their content through an interface.  Whoops!  That's
> > OOP!
>
> There's nothing inherently wrong with OOP but it achieved prominence on
> the back of C and Algol like languages and those implementations of OOP
> systems create issues that other languages simply don't have.  For
> example at least one person
> (http://norvig.com/design-patterns/ppframe.htm) thinks the Gang of Four
> would not be earning a dime of royalty or consulting fees if they used
> a dynamically typed language because most of their patters are trivial
> in other idioms.

The web browser I used to access his powerpoint slides was written in C++.  
PowerPoint (AFAIK) was written in C++.  The mail client I am using was 
written in C++.  The window manager I'm using was written in C++.  His 
critique was written a decade ago.

> What determines the value is the evaluator, what holds it is some
> expression, in this case one with the head Real.

What I really want to know is, given a symbol s with Head[s]===Complex, how 
does the evaluator obtain the precursor values for calculating the returned 
value of Arg[s]?

> > They _are_ the rewrite rules.  At least from the user's perspective.
> > Do you
> > not agree?  See 2.6.2 in the Help Browser.
>
> I agree that that is what they are, and their existence makes it
> possible to write self modifying code pretty easily should the need
> arise.  But they are not necessary.

What are the alternatives without significantly modifying the language?

> > I am willing to bet they are simply bits in a single int variable in
> > the
> > Symbol struct.  What the consequences of their being there are, is a
> > different story.  They may well be arguments to a switch statement.
>
> Again we're thinking on different levels, I'm not really interested in
> what the implementation of Mathematica looks like (I understand it's a
> blend of C and Mathematica itself).  I'm interested in how one would
> model the evaluator in the abstract.

I don't believe you will in general find easy ways using Rule[] to produce 
behavior equivalent to that which results from Attributes being set.  It way 
I view the evaluation is that the evaluator encounters the symbol and queries 
it for certain kinds of data relevant to the current state of the evaluator.  
There is a set of rules to determine the next state depending on the values 
obtained from querying the symbol and the current state of the evaluator. 
After obtaining all the values, the rules are applied, and the evaluator 
transitions to the next state.

> In my job our product is a blend of an interpreted language and an
> internal implementation in another language and I can honestly say that
> there would be no enlightenment for someone seeking to understand the
> interpreted language to look at its implementation.

I really don't care so much whether I know how Mathematica is implemented in 
the Kernel.  I am, however, interested in an abstract model of that 
implementation.  The fact of the matter is, I would probably not like the way 
Mathematica is written.  At least if the MathLink code is any indicator.

> > I don't agree.  The items I listed are the abstract data members of the
> > "type" Symbol.  The evaluator doesn't have rewrite rules any more than
> > a
> > compiler has function definitions.  The rules exist in the expression
> > structure passed to the evaluator.
>
> Regardless of how the evaluator actually works, the question is how you
> can reason about it accurately with respect to generating the correct
> output for a given input (even if you get the algorithmic complexity
> wrong).  I submit that the correct way to think about it is as a
> rewrite system, as others have said.

That is exactly what a CPU is.  But viewing it as simply a rewrite system does 
not help much when the necessary knowledge determing how it works is scattred 
throughout a 1500 page book.  

It would be nice if that level of functionality were explained in a more 
coherent and structured way.  I have books on every language from Old Norse 
to the bash shell.  They almost all have some kind of tree diagram 
representing grammatical structures.  Those tools are completely applicable 
to Mathematica, but I have _never_ seen them used.

Steven

0
hattons (214)
12/11/2005 10:32:46 AM
Reply: