Let me make one more attempt to persuade the committee to change the way
strictness annotations are to be introduced.
First of all, let's recognise that strictness annotations and the seq
function are of enormous importance; this is a vital extension to the
language, not a small detail. Space debugging consists to quite a large
extent of placing applications of seq correctly, and we all know what
dramatic effects space debugging has been able to achieve. The strictness
features are going to be very heavily used in the future.
Recording uses of polymorphic strictness annotations using class Data has
both advantages and disadvantages. A big disadvantage is that curing a space
bug may change the types of many functions in many modules, which at the
least may require a lot of recompilation. The programmer who likes to state
the type of each function will be especially hard hit, of course, which will
unfortunately discourage such a style. But class Data seems to be vital for
cheap deforestation, which is such an important optimisation as to outweigh
the disadvantages.
However, it is an independent question whether or not strictness annotations
should be applicable to function types. And this is where I disagree with
the committee. To quote `Introducing Haskell 1.3',
Every data type, except ->, is a member of the Data class.
In other words, in Haskell 1.3
FUNCTIONS ARE NOT FIRST-CLASS CITIZENS
To design a functional language today, in which this is true, is in my view
deeply mistaken. In the past, I've argued that it will be very frustrating
for those programmers who do discover they need to apply seq to a function
in order to cure a space bug, to find that they are unable to do so. Even
more seriously, programmers weighing up a choice of representation for an
abstract datatype, choosing between a representation as a function or as a
`Data' type, will know that if they choose the function then problems with
space debugging may lurk in the future. Excluding (->) from class Data is a
step away from true `functional' programming towards a style in which
higher-order functions are just a kind of macro.
I see a very great cost in such a philosophical change, and I do not see
that the arguments against strictly evaluating function values are so very
compelling.
Implementation difficulties? hbc has provided it for years, and
even under the STG machine is the problem so very much harder than handling
shared partial applications correctly?
Semantic difficulties? The semantics of lifted function spaces are
perfectly well defined. OK, so it's not the exponential of a CCC --- but
Haskell's tuples aren't the product either, and I note the proposal to
change that has fallen by the wayside.
Weaker strictness analysis? I'd like to hear the effect quantified. How
much slower will Haskell 1.3 run if function spaces are lifted in the
semantics? Will it be measurable? I'm prepared to pay a few percent.
So here's my proposal: change `Introducing Haskell 1.3' to read
Every data type, including ->, is a member of the Data class.
John Hughes