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

**References**:**Re: Re: Types in Mathematica***From:*"Steven T. Hatton" <hattons@globalsymmetry.com>