Services & Resources / Wolfram Forums
-----
 /
MathGroup Archive
2005
*January
*February
*March
*April
*May
*June
*July
*August
*September
*October
*November
*December
*Archive Index
*Ask about this page
*Print this page
*Give us feedback
*Sign up for the Wolfram Insider

MathGroup Archive 2005

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

Search the Archive

Re: Re: Re: Types in Mathematica

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

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


  • Prev by Date: Re: Re: Types in Mathematica thread
  • Next by Date: Re: Re: Re: Types in Mathematica
  • Previous by thread: Re: Re: Re: Types in Mathematica
  • Next by thread: Re: Re: Re: Types in Mathematica