From: stephen@estragon.uchicago.edu (Stephen P Spackman)
Subject: Re: Types, arrays, generality, and notation (was: Fortran90 and Arrays)
Organization: University of Chicago CILS
	<STEPHEN.92Apr14171919@estragon.uchicago.edu>
	<1992Apr15.201453.10255@newshost.lanl.gov>
Date: Thu, 16 Apr 1992 09:21:25 GMT

In article <1992Apr15.201453.10255@newshost.lanl.gov> jlg@cochiti.lanl.gov (Jim Giles) writes:
|In article <STEPHEN.92Apr14171919@estragon.uchicago.edu>, stephen@estragon.uchicago.edu (Stephen P Spackman) writes:
||> A language should not be restricted to a particular problem domain or
||> domains. A good language is _necessarily_ a general purpose language.
|
|Now we _really_ disagree.  I think that the `one size fits all' language
|is impossible with the present technology and probably always will be.
|High-level languages _must_ decide on a target user group and design 
|for that problem domain or they will not be high-level.

This position is (pardon in advance) both defeatist and absurd! If we
take this view we will end up in a world in which it is *not possible*
to write a good, clear programme that involves text processing and
floating point arithmetic, or....

Consider implementing APL. I'm goig to need a parser, and I'm going to
need arrays of complex numbers. Is it *wrong* to want a language
that's competent to both? Is it even hard to imagine such a language?
It won't look like FORTRAN, APL or Lisp, but I don't see why it
shouldn't exist. I don't even see much evidence of its being hard to
achieve.

||> |These are the eight data types all general programming languages should 
||> |support.  By allowing them to be used orthogonally (like: an array of
||> |sequences, or a linked list of records, etc.) you can build any data type
||> |I've ever come across.  Are there any Hoare left out?  In any case, it 
||> |seems perfectly appropriate - even desirable - for each of these to have 
||> |a distinguished syntax to improve legibility of the code.
||> 
||> What about:
||> 	the many variant numeric types, like
||> 		fixeds, bignums, constructive reals, prime power
||> 		product integers, rationals, rationals in irrational
||> 		base, ... not all of which (I can guarantee) are going
||> 		to be "intrinsic" to an implementation
|
|But, given a flexible set of intrinsics, these can be built using 
|records, unions, and/or arrays of those intrinsics.  That, with strict
|type checking and operator overloading permit all of those.

Look at what you wrote. You deemed them unworthy of support. Now you
want to support them? Anyway, you can drop arrays from your list of
useful primitives.  They're just funtions that return lvalues.

But I don't think the issue is whether you can MODEL them. We all know
that's trivial but tedious. The question is can I actually USE them in
my programmes, and still have my programmes be as readable as if tey
were "intrinsic"? Why should the compiler writer have to (or try to!)
anticipate every application the language will eventually be put to?

||> 	numbers with units, like 9.8 m/s2
|
|Units are an enumerated data type.  Numbers with units are a record
|type consisting of a magnitude (possible in some union of numeric
|types), a list of numerator units, and a list of denominator units.
|Arithmetic operators on this record are easily defined (like: plus 
|checks to make sure the units are the same and then adds the magnitudes;
|multiply merges the numerator and denominator lists of its operands,
|removes any that appear in both lists, and takes the product of the 
|magnitude; etc.).

(-: So I have to use DYNAMIC CHECKS? What are you, some kind of
HEATHEN? ;-)

|And, there is another type structuring tool I left out, it might be 
|desirable to define a type with certain things left unspecified and
|allow declarations to contain parameters to finally specify such 
|things.  Such parameterized data types were considered by the Fortran
|committee and were eliminated before public review.

If types are first class then this is just a function again, of
course.

||> 	dependent products
||> 	dependent functions
|
|Describe what you mean here.

Examples. A pair of a number and an array of that many characters is a
dependent product. A function that implements field extraction is a
dependent function. "Dependent" if the type of the right hand field
resp. return value depende on the value of the left hand field resp.
argument.

||> 	type itself
|
|Recent research has shown this to be a bad idea.  What do you propose to

???? For instance? How recent? First I heard.

|do with it?  If you can show reason that it's vitally important, then 
|it should be included in those language designs which are targeted for
|the problem domain in which they are important.

It's how you implement languages like Lisp, where you need to make
records of the form
	[T: TYPE; t: T]
to hold the data. It's how you implement paramterised types, by coding
fuctions like Vector (which has type TYPE -> Nat -> TYPE).

Without it, type constructors have to remain "magic" operations that
the user can't write or extend. That or you need a whole separate
langauage over types, and then you will need a language over THEIR
types and you will need.... (which is the situation in ITT, sort of,
where you always have to guess which Universe to operate in).

|With the addition of functions to my original list, these are all
|capable of being constructed from the tools I gave.  Once constructed,
|the user can give them names and treat them as if they were built-in 
|for the rest of the program - just like any other user defined type.

Will they behave EXACTLY as if they were built in, with all the rights
and priveleges whatsitting thereto? If so, we have no argument, but I
don't believe this is really what you mean.

|Why would one want to explicitly construct continuations?  In functional
|programming languages they are irrelevant and in procedural languages
|they are implicit in the semantics of the language.  I suppose very
|naive conversion programs from procedural to functional languages could
|use them.

Go look at Scheme.

|Depends on what you mean here.  In a functional language, processes 
|are not relevant.  Order of execution is not specified (or specifiable,
|except implicitly) in a functional language, so any parallel operation 
|(or lack thereof) is implicit.  In a procedural language, processes 

Only in a pure functional language is this true. There are plenty of
languages (like, ecch, Lisp) that are functional AND support other
paradigms. In fact, I think it's really stupid not to be at LEAST
functional in the modern - say post-1970 - world. But never mind.

|aren't a data type but a flow control mechanism.

Their representations are objects in a type or types. Just as with
functions (which are control mechanisms if anything is!).

||> 	times
|
|You mean like 8:00 AM?  What are the properties of this data type?
|
||> 	terminals
||> 	people
|
|Physical objects, I admit, cannot be constructed of software.

But, just like processes, they need to be represented TO the software.

|
||> [...etc. etc. ...]
|
|The bottom line is that if you can design a language which supports a
|given data type, then I can construct such that data type using the tools
|I have listed.  Or, are you claiming that you've designed a language
|that's beyong Turing equivalent capabilities?

Look, do we have to keep saying this? I can write ANY PROGRAMME YOU
LIKE in the assembly language of a processor with only one
instruction. I could probably even get by with cube root and exclusive
or to exponent as that instruction. The question is WHAT IS EASY AND
USABLE in the *source notation*? Can you provide me with surface
syntax for 8:00am that is readable and practical? Can you provide me
with enough type system support that I don't need to know if my sets
are implemented with arrays or not? *Not even when writing a literal
for one*? Can I introduce control constructs with the same
relationships to my types that IF has to Booleans or FOR has to
Integers?

||> [...]
||> THEN HOW DO I INTRODUCE A NEW KEYWORD? I tell you, it's a reserved
||> mechanism. How am I failing to communicate this idea? If I can't make
||> one, but the language implementor does, it's reserved.
|
|Oh.  I see.  You're one of those people who see no value in a standardized
|notation.  Changing the keywords and other basic characteristics of a

Ad hominem alert. You're clearly the kind of person who eats
odor-eaters for breakfast, *I'm* sure. ;-).

|programming language is like changing the grammar of English - it's
|great as long as you only talk to yourself.  Languages which allow
|the user to define such things tend to be mutually incomprehensible
|even among strong supporters of those languages.  Language design is
|a compromise (on several points simultaneously).  In this case, the
|compromise is between flexibility and standardization of syntax.

*I'm not talking about syntax*. I'm talking about choice of
identifiers. I said "how do I introduce a new KEYWORD", not "how do I
introduce a new PRODUCTION". Why should it be any more confusing for
me to introduce a new construction AT <time> DO <stmt> END than it is
for me to introduce a new function atDo(<time>, <stmt>)? They're just
names, and you define new names.

|There are some aspects of the syntax of a language which I think should
|be beyond the ability of the user to change.  This promotes better 
|understanding _between_ programmers.  If you never work with other 
|people or you never read other people's code this may be irrelevant
|to you.  It's not to me.

I repeat: I have never once suggested changing the SYNTAX of the
language. Not since I was twenty have I made such a suggestion (though
there are perfectly good and readable languages that provide some
capabilities in that direction, as it happens. I just don't like them,
for much the reasons you give: the cognitive load is a bit steep if
the programmmer makes a bad choice along the way).

||> [... Fortran 90 operator overloading rules and our proposed extension ...]
||> 
||> Sure took long enough! But hoorah. Can the overloads be resolved off
||> opaque types, or do they see the implementations?
|
|What do you mean by `opaque' types?  Also, what do you mean by "Sure
|took long enough"?  This thread has been going (now under several names)
|for months now.  My second or third article mentioned these operator
|overloading rules and our proposed extensions to them.

Meaning, it's taken 20 years. And I'm afraid I missed the earlier
discussion, I was working on my thesis. Sorry.

||> Integer arithmetic slower than floating point? You're kidding!  [...]

|Yes.  Integer multiplies require the whole product to be formed, for
|example.  Many Floating-point implementations do not (though not doing

Would this be hard to fix?

|so increases round-off error a bit - such implementations are not IEEE
|conforming).  An integer multiply on the Cray would probably take twice 
|as long as the float product for the same number of significant bits.
|Integer adds and subtracts are a little faster (_very_ little) than 
|floating-point ones.  Integer divides are worse (floating-point
|implementations often use a Newtons's iteration - which would not
|be accurate enough for fixed-point).  Once again, this trade-off is
|between relative error in a calculation for floating-point vs. 
|absolute error in fixed-point.  Relative error tends to be more
|important more often.

But none of this has to do with inherent properties of floating point
numbers, it has to do with how the mantissas are manipulated, right?
Wouldn't they be more useful unbundled? So they could be used for
fixed point and for fractions-of-1 without paying for the often
undesirable exponent field?

|A wider word doesn't help if the problem is caused by the fact that 
|your algorithm required good _relative_ error characteristics on a
|wide variety of magnitudes rather than good absolute error characteristics
|on the narrow range of magnitudes that fixed-point provides.  Or, do 
|you recommend that _every_ data object has a separate fixed-point
|type with a specially tuned scale factor (in which case, every 
|operation will be recomputing the scale factors - that is, simulating
|float in software).

Yep. Seems to me that the suual arguments about exposing things to the
compiler should apply. With a few more bits we could eliminate a lot
of the exponent calculations as static. No?

I *may* be very wrong, but I've never met anyone who was willing to
have a reasoned conversation with me about it. Everyone seems either
to agree with me in principle, sigh, and say "but you have to
understand that the FORTRAN community holds the hardware community by
the balls, because they pay for our research", or they start foaming
at the mouth and saying "you've GOT to have floating point. It isn't a
COMPUTER without floating point. How can you have NUMBERS without
floating point, it isn't just my weather calculations, how could you
write BANKING code without floating point....". But I'm still looking.
Thanks, incidentally, for the intelligent remarks above.

||> [... reduce can't automatically select identity for all operators ...]
||> That was my point. Identity is part of the programmer-provided
||> semantics, and you mustn't go locking people into a default that is
||> actually meaningless half the time.... This is one you MUST be able to
||> specify, because the compiler DOESN'T know. Or are you suggesting that
||> reduction should only be.... Never mind.
|
|The notation you gave in your earlier post implied that the compiler was
|_automagically_ deciding what the identity for various operators was. 
|You gave `+' and `min' as examples if I recall correctly.  You had the 
|syntax of the two done identically and claimed the compiler would select 
|zero as the identity for plus and would require a non-empty array for 
|reducing `min'.  How does the compiler _know_?  How does the user intervene 

What? I never. I required the specification of the identity in all
cases. I know this, because otherwise I would have had to talk about
type objects and I know I didn't do this. In fact, this subthread
started when you said to me that you could understand what I'd put in
the identity argumet for +, viz: 0, but that you couldn't see what I'd
choose for something that didn't HAVE an identity. But that was why
min was one of my examples: it doesn't HAVE an identity, but you can
use the first element of the array (which is why the array must be
nonempty in this case, so it can have a first element).

|if he wants something else?  Your example gave no indication at all about
|these issues.  My counterexample made it clear that the user had specific
|control at the site of the reduce.

Nono, you're just forgetting my proposal. I had a topology argument
like you, an initial value/identity, a function and an array. Honest!

|If you intended that your method allow the user control over what the
|identity element for user defined functions was, you should have shown 
|_how_ the user exercises that control.  Your examples _implied_ that
|the compiler somehow automatically `knew' what to do.

Hell no, it was an argument to a function and you get to choose it.
It's the APL guys who have trouble with this one. (Iverson once worked
out the solution to this, which is to give functions _attributes_ like
"identity" and "inverse", but I don't think it was ever implemented. I
thought it was cute, myself).
----------------------------------------------------------------------
stephen p spackman         Center for Information and Language Studies
stephen@estragon.uchicago.edu                    University of Chicago
----------------------------------------------------------------------
Xref: sparky comp.lang.misc:1744 comp.lang.functional:499 comp.object:1778