
Prompted by recent discussion on the Hat mailing list about the problems of type-defaulting, I have added two new proposals for this issue to the Haskell-prime wiki at: http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting The main new proposal is a different way of specifying defaults, which includes the name of the class being defaulted (thus allowing user-defined classes to play this game), but unlike the original proposal, permits only one type to be specified per class. The rules are therefore also simpler, whilst still (I believe) capturing the useful cases. A secondary proposal is to generalise defaults from having module-local scope, to global scope. This would allow library authors to capture the intended behaviour of their own classes and types, without bothering the library users. (Also, whilst removing module-local redefinition of defaults, the proposal would instead permit function-local re-definition.) I am less convinced of the need for this proposal, but in the spirit of exploring the design space, I thought it worth bringing up. Regards, Malcolm

remember that defaulting does not happen class-by-class at the moment. If you have (Eq a, Fractional a) where 'a' is unconstrained, the current rules pick the first type T in the defaulting list that satisfies all the constraints (Eq T, Fractional T) I don't know what would that would mean if Eq had a different defaulting list than Fractional, as you propose. Another issue that Haskell' needs to address is what defaulting means when you have multi-parameter type classes. Simon | -----Original Message----- | From: haskell-prime-bounces@haskell.org [mailto:haskell-prime-bounces@haskell.org] On Behalf Of | Malcolm Wallace | Sent: 20 November 2006 12:06 | To: haskell-prime@haskell.org | Subject: defaults | | Prompted by recent discussion on the Hat mailing list about the problems | of type-defaulting, I have added two new proposals for this issue to the | Haskell-prime wiki at: | | http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting | | The main new proposal is a different way of specifying defaults, which | includes the name of the class being defaulted (thus allowing | user-defined classes to play this game), but unlike the original | proposal, permits only one type to be specified per class. The rules | are therefore also simpler, whilst still (I believe) capturing the | useful cases. | | A secondary proposal is to generalise defaults from having module-local | scope, to global scope. This would allow library authors to capture the | intended behaviour of their own classes and types, without bothering the | library users. (Also, whilst removing module-local redefinition of | defaults, the proposal would instead permit function-local | re-definition.) I am less convinced of the need for this proposal, but | in the spirit of exploring the design space, I thought it worth bringing | up. | | Regards, | Malcolm | _______________________________________________ | Haskell-prime mailing list | Haskell-prime@haskell.org | http://www.haskell.org/mailman/listinfo/haskell-prime

Simon Peyton-Jones
remember that defaulting does not happen class-by-class at the moment.
Yes, and this is exactly the point of the proposal (#2). It makes sense (to me at least) to change the rules so that defaulting happens per-class. At the moment, it _can_ occur for any class, provided only that the type is _also_ constrained to be an instance of Num. It is a very strange rule, and one that I guess very few people understand fully, yet I hope to show that one can subsume it entirely by introducing a different but more general rule, that is easier to understand.
If you have (Eq a, Fractional a) where 'a' is unconstrained, the current rules pick the first type T in the defaulting list that satisfies all the constraints (Eq T, Fractional T). I don't know what would that would mean if Eq had a different defaulting list than Fractional, as you propose.
Well, for one thing I don't like the idea of a "list" of potential defaults. My suggestion is that there should be a single default type per class. If more than one class is involved, then either their defaults should agree, or only one of them in fact declares a default. I claim that this would be sufficient for every extant use case. But I would quite like to have some evidence to back up this claim! If anyone actually uses explicit defaults in their programs, I would be interested in seeing some real data on this. Feel free to submit such example decls to my email address. I suspect that almost no-one uses defaults except for the original motivating case of literal numbers. If so, then even quite a big change in this area would hurt very few people, provided it was backward compatible with the literal number thing.
Another issue that Haskell' needs to address is what defaulting means when you have multi-parameter type classes.
Yes, I was going to mention that myself on the wiki, but it slipped my mind again. So here is one idea. If you have a single default type per class in the SPTC scenario, then you would have a single default _relation_ of types in the MPTC case. The default decl could be made to look rather like an instance decl: default Num Integer default Fractional Double class Dual d c where ... default Dual Binary [Bool] except, unlike instances, you are permitted only one of them. Regards, Malcolm

On 11/20/06, Malcolm Wallace
Well, for one thing I don't like the idea of a "list" of potential defaults. My suggestion is that there should be a single default type per class. If more than one class is involved, then either their defaults should agree, or only one of them in fact declares a default.
I claim that this would be sufficient for every extant use case. But I would quite like to have some evidence to back up this claim! If anyone actually uses explicit defaults in their programs, I would be interested in seeing some real data on this. Feel free to submit such example decls to my email address. I suspect that almost no-one uses defaults except for the original motivating case of literal numbers. If so, then even quite a big change in this area would hurt very few people, provided it was backward compatible with the literal number thing.
Ah, another fine opportunity to use Google Code Search. And even more so now that it supports Haskell code! http://www.google.com/codesearch?hl=en&lr=&q=%5Edefault%5C+%3F%5C%28+lang%3Ahaskell&btnG=Search Cheers, Josef

"Josef Svenningsson"
If anyone actually uses explicit defaults in their programs, I would be interested in seeing some real data on this.
Ah, another fine opportunity to use Google Code Search. And even more so now that it supports Haskell code!
An excellent suggestion, thank you! Several things strike me about this data: * Very few projects use defaulting (only 30 results show up, and I am the author of 6 of those). * I had forgotten about the important need to turn _off_ defaulting (now added to my proposal). * Extant uses fall into 3 main categories: . turning off defaults because Hat and Buddha cannot handle them well . changing default(Integer) to default(Int) for compatibility with pre-Haskell-1.4 behaviour, or for performance reasons (in Hugs) . introducing a new numeric type (e.g. GLfloat, Number) Of course, what the extant data cannot show is how authors would _like_ to have used defaulting, but were prevented from doing so by the language spec. Well, maybe the Hat and Buddha examples hint at it. I can also imagine that it would be useful to have per-class defaults for user-defined classes in something like QuickCheck or SmallCheck. It is tedious to need to add to your property specification some exact type signature to constrain the polymorphic values such that the system can generate some of them. It would be so much easier to be able to say default Arbitrary Int or default Serial Bool and then the system could generate appropriate test cases without the extra human work of adding lots of signatures. Regards, Malcolm P.S. updated proposal here: http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting

| Well, for one thing I don't like the idea of a "list" of potential | defaults. My suggestion is that there should be a single default type | per class. If more than one class is involved, then either their | defaults should agree, or only one of them in fact declares a default. Ah, I missed that. Suppose I have default Eq Integer default Fractional Float and I have (Eq a, Fractional a). Does 'a' resolve to Integer or to Float? Perhaps a few examples on the proposal page would be useful for readers? Simon

Simon Peyton-Jones
| My suggestion is that there should be a single default type | per class.
Ah, I missed that.
I suppose, because the proposed new rule is so simple and short, it is rather easy to miss its implications, especially if you are used to thinking in terms of the existing more complicated rule.
Suppose I have default Eq Integer default Fractional Float and I have (Eq a, Fractional a). Does 'a' resolve to Integer or to Float? Perhaps a few examples on the proposal page would be useful for readers?
The proposed rule is that defaulting applies *after* simplification of the context. So, although you initially infer (Eq a, Fractional a) => a but after simplification, this becomes (Fractional a) => a so there is a single class to be defaulted, and Float is chosen. Here are some more examples. default Ord Integer default Fractional Float (Ord a, Fractional a) => a --> static error, because Ord is not a superclass of Fractional, so the context does not simplify, and the default types disagree. default Bounded Int default Ord Int (Ord a, Bounded a) => a --> default is Int, because even though the context does not simplify, the classes involved do agree on which default to choose. default Bounded Int default Ord Int (Ord a, Bounded a, Show a) => a --> default is Int, same as above, except for the extra constraint Show a. There is no default declared for Show, so the remaining context is used to make the choice. (Show a, Read a) => a --> static error, because there are no defaults declared for any of the classes involved. Regards, Malcolm

I think this thread is discussing your proposal 2, ignoring 1. | default Ord Integer | default Fractional Float | (Ord a, Fractional a) => a | | --> static error, because Ord is not a superclass of Fractional, so | the context does not simplify, and the default types disagree. Ah, that's the example I was trying to get at. OK, so your rule is that both must give the same answer. Fine. | > Suppose I have | > default Eq Integer | > default Fractional Float | > and I have (Eq a, Fractional a). Does 'a' resolve to Integer or to Float? Perhaps a few examples on | the proposal page would be useful for readers? | | The proposed rule is that defaulting applies *after* simplification of | the context. So, although you initially infer | (Eq a, Fractional a) => a | but after simplification, this becomes | (Fractional a) => a | so there is a single class to be defaulted, and Float is chosen. Delicate, this. Suppose you had (Eq a, Foo a b, Num b) If I start with (Eq a) I might choose Integer. But if I start with Num b, I might choose default b=Float. Suppose I have instance Fractional a => Foo a Float Now I simplify (Foo a Float) to get Fractional a, and now I should choose a=Float. Not very confluent. Tricky Simon

Simon Peyton-Jones
I think this thread is discussing your proposal 2, ignoring 1.
Indeed. Proposal 1 was from John Meacham, and I have edited it further to show how even simple lists lead to non-confluence. I had hoped that by simplifying from lists to unique types (in proposal 2), that we could regain confluence. But your example below shows that I have not yet fully achieved that goal.
Suppose you had (Eq a, Foo a b, Num b) If I start with (Eq a) I might choose Integer. But if I start with Num b, I might choose default b=Float. Suppose I have instance Fractional a => Foo a Float Now I simplify (Foo a Float) to get Fractional a, and now I should choose a=Float.
Ah, but here you have an MPTC: Foo a b. Currently, Haskell'98 has no story at all for how defaulting would work over MPTCs. According to the Report, the type variable 'a' is not defaultable, because it is not directly constrained by a numeric class. OK, so if we change the example slightly to satisfy that condition, does Haskell'98 say anything then? ( Fractional a, Foo a b, Num b ) Of course, it still falls foul of the rule that a variable 'v' can only be constrained in the form (C v), but setting that aside also... So if I have instances: instance Foo Float Integer instance Foo Double Int and default (Int,Integer,Float,Double) then which are the "first" types for 'a' and 'b' from the list to satisfy all the constraints? The possible choices are incomparable with each other for "firstiness". My proposal for defaulting MPTCs does not fix this. I had failed to consider the case that defaulting one of the variables may cause an instance to become available, which might immediately constrain the other variable(s) further. The order in which you choose to default variables might therefore give you different constraints on the other variables. One solution might be simply to disallow defaulting over MPTC. (I can't immediately think of any useful applications.) Another solution might be to say that defaulting will only occur *if* it is confluent, i.e. the compiler should try all possible orderings in which to default variables, and if they do not come up with the same answer, then reject the program. Regards, Malcolm

haskell-prime-bounces@haskell.org wrote:
Simon Peyton-Jones
writes: My suggestion is that there should be a single default type per class.
Ah, I missed that.
I suppose, because the proposed new rule is so simple and short, it is rather easy to miss its implications, especially if you are used to thinking in terms of the existing more complicated rule.
Suppose I have default Eq Integer default Fractional Float and I have (Eq a, Fractional a). Does 'a' resolve to Integer or to Float? Perhaps a few examples on the proposal page would be useful for readers?
The proposed rule is that defaulting applies *after* simplification of the context. So, although you initially infer (Eq a, Fractional a) => a but after simplification, this becomes (Fractional a) => a so there is a single class to be defaulted, and Float is chosen.
Is your proposal supposed to be backwards compatible with Haskell 98 for programs that don't have default declarations? If so, then I offer a counter example: toRational pi will default pi to Double in Haskell 98, but will be an error under your proposal, because the two constraints (Real and Floating) disagree on the default. dflt.hs:3:7: Warning: Defaulting the following constraint(s) to type `Double' `Real a' arising from use of `toRational' at dflt.hs:3:7-19 `Floating a' arising from use of `pi' at dflt.hs:3:18-19 In the expression: toRational pi In the definition of `test': test = toRational pi You can generate more examples using Enum/Fractional combinations, but it's dubious whether Float & Double should be instances of Enum anyway. Cheers, Simon

Simon Marlow
Is your proposal supposed to be backwards compatible with Haskell 98 for programs that don't have default declarations?
Yes, it is supposed to be backwards compatible.
If so, then I offer a counter example: toRational pi will default pi to Double in Haskell 98, but will be an error under your proposal, because the two constraints (Real and Floating) disagree on the default.
Well spotted. So there are some expressions that are defaulted in H'98 but would not pass type-checking with my proposal. (1) Are examples like this common? I am guessing not. You mention Enum/Fractional combinations, but arguably Float and Double do not belong in Enum anyway. (2) The new rule is conservative - it does not silently change the semantics, but it does reject more programs. Such programs are easily fixed by adding a type signature. If these two points are valid, then I think the slight loss of backward compatibility is acceptable? Regards, Malcolm

haskell-prime-bounces@haskell.org wrote:
Simon Marlow
wrote: Is your proposal supposed to be backwards compatible with Haskell 98 for programs that don't have default declarations?
Yes, it is supposed to be backwards compatible.
If so, then I offer a counter example: toRational pi will default pi to Double in Haskell 98, but will be an error under your proposal, because the two constraints (Real and Floating) disagree on the default.
Well spotted. So there are some expressions that are defaulted in H'98 but would not pass type-checking with my proposal.
(1) Are examples like this common? I am guessing not. You mention Enum/Fractional combinations, but arguably Float and Double do not belong in Enum anyway.
(2) The new rule is conservative - it does not silently change the semantics, but it does reject more programs. Such programs are easily fixed by adding a type signature.
If these two points are valid, then I think the slight loss of backward compatibility is acceptable?
I don't know whether this is an acceptable loss of backwards compatibility, perhaps it is. But I spotted the problem because it looks (to me) like the current Haskell 98 rule is designed specifically to handle cases like this. Would you mind updating the wiki page? I don't think it's too clear on the need for constraint simplification before applying your defaulting rules either. Cheers, Simon

Simon Marlow
If so, then I offer a counter example: toRational pi
If these two points are valid, then I think the slight loss of backward compatibility is acceptable?
I spotted the problem because it looks (to me) like the current Haskell 98 rule is designed specifically to handle cases like this.
I agree that having to write toRational (pi::Double) is somewhat ugly.
Would you mind updating the wiki page? I don't think it's too clear on the need for constraint simplification before applying your defaulting rules either.
I have added your counter example to the wiki. But I'm not sure how to make the need for constraint simplification clearer. 3 out of the 7 sentences in the proposal describe it, and 3 out of the 5 examples mention its role. What do you think is missing? Regards, Malcolm

On Mon, Nov 20, 2006 at 12:05:46PM +0000, Malcolm Wallace wrote:
Prompted by recent discussion on the Hat mailing list about the problems of type-defaulting, I have added two new proposals for this issue to the Haskell-prime wiki at:
http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting
I don't see a proposal to remove defaulting defaulting altogether on that page - has that been discussed already? Am I the only one who puts an explicit type signature in whenever my compiler warns me that it is having to do some defaulting? And probably 99% of those would be unnecessary if (^)'s second argument was an Int, with a genericPower (or whatever) function providing the current type signature (analogous to, for example, (!!) and genericIndex). Defaulting is one wart I would be glad to be rid of. Thanks Ian

On 28/11/2006, at 11:28 AM, Ian Lynagh wrote:
On Mon, Nov 20, 2006 at 12:05:46PM +0000, Malcolm Wallace wrote:
Prompted by recent discussion on the Hat mailing list about the problems of type-defaulting, I have added two new proposals for this issue to the Haskell-prime wiki at:
http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting
I don't see a proposal to remove defaulting defaulting altogether on that page - has that been discussed already?
Am I the only one who puts an explicit type signature in whenever my compiler warns me that it is having to do some defaulting? And probably 99% of those would be unnecessary if (^)'s second argument was an Int, with a genericPower (or whatever) function providing the current type signature (analogous to, for example, (!!) and genericIndex).
Defaulting is one wart I would be glad to be rid of.
I would also be happy if it was removed. My main reasons are: 1) It makes teaching Haskell more difficult, because it is a special case mechanism. I would prefer consistency here. 2) It makes source-to-source program transformations more difficult, as found in Hat etc. 3) I have found it easy to avoid with the addition of type annotations. I don't write a lot of numeric code, so the benefits I personally get from defaulting have so far been minimal, and that has coloured my view. Others may find it more useful. Cheers, Bernie.

Bernie Pope
I don't see a proposal to remove defaulting defaulting altogether on that page - has that been discussed already?
Defaulting is one wart I would be glad to be rid of.
I would also be happy if it was removed.
Me too, in some ways. But...
1) It makes teaching Haskell more difficult, because it is a special case mechanism. I would prefer consistency here.
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types Prelude> 1+2 into Hugs, and gets the response Unresolved overloading: Num a Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
2) It makes source-to-source program transformations more difficult, as found in Hat etc.
Sure, I'd be glad to improve that. Removing defaults altogether would solve the problem for the average user. But power users like Duncan would like to _extend_ defaulting to work over GUI type classes, and that too seems a reasonable request to me. Does my proposal for revision of defaults allow that, and still make Hat-style transformation easier? Yes, I think so. Regards, Malcolm

On Wed, Nov 29, 2006 at 06:08:14PM +0000, Malcolm Wallace wrote:
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types
Prelude> 1+2
into Hugs, and gets the response
Unresolved overloading: Num a
Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
Following a suggestion of Ralf Hinze, GHCi and Hugs already perform more defaulting on interpreted expressions than on definitions in modules (where they follow Haskell 98). Thus "reverse []" just works, instead of provoking ERROR: Cannot find "show" function for: *** expression : reverse [] *** of type : [a] See http://www.haskell.org/ghc/docs/latest/html/users_guide/ch03s04.html#extende... So if defaulting were removed from the language it could still be done at the interpreter prompt.

On 30/11/2006, at 5:08 AM, Malcolm Wallace wrote:
Bernie Pope
wrote: I don't see a proposal to remove defaulting defaulting altogether on that page - has that been discussed already?
Defaulting is one wart I would be glad to be rid of.
I would also be happy if it was removed.
Me too, in some ways. But...
1) It makes teaching Haskell more difficult, because it is a special case mechanism. I would prefer consistency here.
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types
Prelude> 1+2
into Hugs, and gets the response
Unresolved overloading: Num a
Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
Yes, numerical expressions do cause trouble from day one --- especially so when the teaching staff are not Haskell experts (as is sometimes the case). But I don't think defaulting necessarily makes the job of teaching any easier, and in my opinion it just creates its own problems. At some point, very early on, perhaps also on day one, you are going to tell students about types (at least some of the base types). So you write: Prelude> :t 1+2 1+2 :: Num a => a What the? Now you have to explain what this means _and_ you have to explain why we were able to evaluate it as above, even though it is ambiguous. Type classes are often mysterious to the beginner, but this seemingly inconsistent behaviour just makes them appear even more magical. I don't think it would hurt too much to have "1+2" rejected by the type checker outright. You can ask for the type, discuss the ambiguity, and then fix it with a type annotation: Prelude> 1+2 :: Int Students are going to bump into this issue sooner or later, and it is best they are prepared from the start, at the expense of a slightly more involved discussion in the first lesson.
2) It makes source-to-source program transformations more difficult, as found in Hat etc.
Sure, I'd be glad to improve that. Removing defaults altogether would solve the problem for the average user. But power users like Duncan would like to _extend_ defaulting to work over GUI type classes, and that too seems a reasonable request to me. Does my proposal for revision of defaults allow that, and still make Hat-style transformation easier? Yes, I think so.
A compromise is to turn defaulting off "by default". This would mean that if you want defaulting you have to ask for it. The question then would be: does defaulting get exported across module boundaries? I would be inclined to say "no", but there may be compelling arguments for it. Cheers, Bernie.

On Thu, 2006-11-30 at 12:21 +1100, Bernie Pope wrote:
A compromise is to turn defaulting off "by default". This would mean that if you want defaulting you have to ask for it. The question then would be: does defaulting get exported across module boundaries? I would be inclined to say "no", but there may be compelling arguments for it.
If it's on a per-class basis then it would be reasonable to allow the default to be exported, no? Then you just have to argue about if the default Prelude should export defaults for the Num and other standard classes. For my GUI OOP inheritance hierarchy use-case I'd certainly want to export the default. It'd be pretty useless otherwise (I don't mean in general, just for this use-case). Duncan

Malcolm Wallace wrote:
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types
Prelude> 1+2
into Hugs, and gets the response
Unresolved overloading: Num a
Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
I propose we abandon "teaching" arguments for design choices entirely. There are two reasons for this. Firstly, they don't apply to the majority of Haskell users, and secondly, they almost always misapprehend the language-learning process. To give you a vague example, when I was learning ML, what appealed to me was the sense of cleanliness and purity about the language. Any apparent weirdness was fine, as long as I could discover the elegant reason behind it. This right up until finding out about references, which bothered me so much that I dropped it and learnt Haskell instead. That something might confuse the beginning user should count for nothing if it does not annoy the more experienced user. -- Ashley Yakeley

On 30/11/2006, at 3:36 PM, Ashley Yakeley wrote:
Malcolm Wallace wrote:
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types Prelude> 1+2 into Hugs, and gets the response Unresolved overloading: Num a Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
I propose we abandon "teaching" arguments for design choices entirely. There are two reasons for this. Firstly, they don't apply to the majority of Haskell users, and secondly, they almost always misapprehend the language-learning process.
To give you a vague example, when I was learning ML, what appealed to me was the sense of cleanliness and purity about the language. Any apparent weirdness was fine, as long as I could discover the elegant reason behind it. This right up until finding out about references, which bothered me so much that I dropped it and learnt Haskell instead.
That something might confuse the beginning user should count for nothing if it does not annoy the more experienced user.
Whilst I agree with some of your sentiment, I think that this argument is too extreme. On a general level, for a language with a relatively small community, Haskell has been rather successful as a vehicle for education. I don't think we should underestimate the impact that this exposure has had on the language. Teachers of Haskell, and students of Haskell, are important members of the community, and their opinions are not irrelevent. Having said that, I agree that we should be careful with arguments based on the grounds of ease of teaching, especially so when we don't have good data to back them up. In many cases, I think that we should fix the compilers first, before we try to fix the language, in particular the error messages generated by them. You can't please all of the people all of the time, so there will naturally be situations where different user groups have competing interests. If a design decision would impinge on both the experienced users and the beginners, then, of course, a value judgement has to be made. I see no reason to rule out the needs of teaching altogether, especially in cases where there is no real conflict with other user groups. Cheers, Bernie.

On Wed, 29 Nov 2006, Ashley Yakeley wrote:
That something might confuse the beginning user should count for nothing if it does not annoy the more experienced user.
This experienced user regularly uses a haskell interpreter for a desk calculator, not to mention for producing readable budgets that show all the working. Removing defaulting would make that extremely tedious. -- flippa@flippac.org "The reason for this is simple yet profound. Equations of the form x = x are completely useless. All interesting equations are of the form x = y." -- John C. Baez

Hello,
On 11/30/06, Philippa Cowderoy
On Wed, 29 Nov 2006, Ashley Yakeley wrote:
That something might confuse the beginning user should count for nothing if it does not annoy the more experienced user.
This experienced user regularly uses a haskell interpreter for a desk calculator, not to mention for producing readable budgets that show all the working. Removing defaulting would make that extremely tedious.
I do what you suggest all the time (I mean using Hugs as a calculator) and I agree that it would be annoying without some sort of defaulting. However, I am not sure that this particular use justifies the addition of defaulting to the _language_. For example, it is possible that defaulting is implemented as a switch to the command-line interpreter. By the way, I agree with Ashley that the "it is hard to teach" argument is over-used. -Iavor

On Thu, 30 Nov 2006, Iavor Diatchki wrote:
Hello,
On 11/30/06, Philippa Cowderoy
wrote: This experienced user regularly uses a haskell interpreter for a desk calculator, not to mention for producing readable budgets that show all the working. Removing defaulting would make that extremely tedious.
I do what you suggest all the time (I mean using Hugs as a calculator) and I agree that it would be annoying without some sort of defaulting. However, I am not sure that this particular use justifies the addition of defaulting to the _language_. For example, it is possible that defaulting is implemented as a switch to the command-line interpreter.
The more generalised Haskell-as-spreadsheet-replacement might, as that creates source files. -- flippa@flippac.org Performance anxiety leads to premature optimisation

Hello Iavor, Thursday, November 30, 2006, 8:41:43 PM, you wrote:
However, I am not sure that this particular use justifies the addition of defaulting to the _language_. For example, it is possible that defaulting is implemented as a switch to the command-line interpreter.
how about using Haskell for scripting? i find it as great alternative to perl/ruby, particularly because i don't want to remember two languages, particularly because of great data processing instruments -- Best regards, Bulat mailto:Bulat.Ziganshin@gmail.com

Hello,
On 11/30/06, Bulat Ziganshin
Hello Iavor, how about using Haskell for scripting? i find it as great alternative to perl/ruby, particularly because i don't want to remember two languages, particularly because of great data processing instruments
I am speculating, but I suspect that the uses of defaulting in a Haskell program (e.g. a script) are a lot fewer than when one uses Hugs as a calculator. In addition, as people already mentioned, ambiguities can be resolved with type signatures.We already have to do this anyway when defaulting does not apply (e.g., if any user defined classes are involved). -Iavor

defaulting can also be used for non-standard arithmetic in teaching (not something you want to let loose on students who you don't want to know about type classes, though, so be careful where you demonstrate this;-): http://www.cs.kent.ac.uk/people/staff/cr3/toolbox/haskell/R.hs Main> foldr1 (*) [1..5] (1 * (2 * (3 * (4 * 5)))) Main> foldl (*) 1 [1..5] (((((1 * 1) * 2) * 3) * 4) * 5) Main> foldr (*) 1 [1..5] (1 * (2 * (3 * (4 * (5 * 1))))) Main> map (+) [1..4] [\x->(1 + x),\x->(2 + x),\x->(3 + x),\x->(4 + x)] Main> map (1+) [1..4] [(1 + 1),(1 + 2),(1 + 3),(1 + 4)] Main> map (1+) [1..4] :: [Int] [2,3,4,5] this was written long ago, with Hugs in mind, where the defaulting applies to the interactive loop - with GHCi, you'll need to add -fglasgow-exts, and still don't get the defaulting interactively (?), so you'll need to write the type annotations: *Main> foldr (-) 0 [1..4] :: R Int (1 - (2 - (3 - (4 - 0)))) *Main> foldl (-) 0 [1..4] :: R Int ((((0 - 1) - 2) - 3) - 4) of course, this would be fine if defaults could be set in the interactive loop itself, so you don't need defaults here, and one might argue that having to give type annotations is annoying, but instructive.. personally, I use default very rarely, but that kind of reasoning has never been a good argument for excluding a feature that others like. I would agree, however, that the monomorphism restriction should go (warning only), so that defaulting cannot change my 1 :: Num a => a constants from Behaviours to Integers; with DMR gone, there may be less need for defaulting, but I would also agree that defaulting should be generalized so that its current use becomes a special case of disambiguating overloading for a whole module/program/session, without having to specialize the type-signatures everywhere in the code. and yes, teaching is important, and Haskell is not only about teaching, so teaching needs need to be addressed like the needs of any other important Haskell application area: by optional, but widely supported, domain-specific libraries/packages/flags/syntax/.. Just my (2 :: Num a => a), Claus

and yes, teaching is important, and Haskell is not only about teaching, so teaching needs need to be addressed like the needs of any other important Haskell application area: by optional, but widely supported, domain-specific libraries/packages/flags/syntax/..
oh, and it might be useful to look at the interests of Haskell textbook authors in a different way: if I was an author of a Haskell textbook, and I had the foresight to rely not on "the" prelude or "the" standard libs (because they will both change, among other things, before the first edition of that book gets out of circulation..), what help could Haskell' or Haskell'' could give me? here are a few examples to get the discussion going - imagine things like: -package Thompson fromInt = fromInteger -- easy error message += explanation -- hmm? -package Hudak module SOE -- ouch, years of hard work by several hackers, -- and still mostly trouble and pain libaries += portable graphics and stuff -package Bird syntax pattern += (n+k) -- hmm -package Helium -- is there a book to go with this? language -= type classes -- not really easy? (error messages -= abstract messages) += specific messages -package NewKidOnTheBlock everything = haskell' and state-of-2006 -- to be adapted as things change as we can see from this exhaustive survey.. okay, I'm just kidding!-) but it seems that there are quite a few things that *are* important to Haskell teaching, and have disturbed Haskell textbook authors, that ought to be investigated as language and library design and maintainance problems - though it is a bit late in the day for Haskell', perhaps the committee and current authors could think of a roadmap, so that authors and implementers have something to aim for? and of course, so that these issues are adressed properly, rather than returning here as limitations on the design process? of course, that's no bikeshed, but still, perhaps people have an opinion?-) claus

Malcolm Wallace wrote:
Unfortunately, I suspect that teaching is _the_ major use-case for defaulting. Imagine, day one, lesson one, a student types
Prelude> 1+2
into Hugs, and gets the response
Unresolved overloading: Num a
Huh? This is lesson one, and you already need to tell students about type classes and overloading, before you have even covered simple expressions fully? I am certain this is the reason why defaulting was introduced.
I remember someone proposing a Beginner's Prelude. Such a Prelude could solve almost all the teaching problems that are regularly brought against making the language or the standard libraries more generic and orthogonal (and thus more useful for the experienced programmer, and additionally to those of us who, even as beginners, rather accept "apparent weirdness, as long as [they] could [eventually] discover the elegant reason behind it", as Ashley so nicely put it). Witness the eternal 'map' vs. 'fmap' argument: Beginner's Prelude could define map::(a->b)->[a]->[b] and /not/ import the Functor class, whereas serious users would import Control.Functor or whatever and have the more generic map from class Functor. In the particular case that's been discussed here (defaulting), the solution is to have Integer be the only integral type in the new Prelude. It has also been argued that the experienced programmer doesn't need any Prelude at all, she can import all the stuff she needs explicitly; the penalty for that would be small since any non-trivial piece of code needs to import lots of modules explicitly anyway. The logical consequence is to rename Beginner's Prelude back to just Prelude. One proposal I remember was to implicitly import the Prelude (and I'd say this should be the stripped down Beginner's version) only for modules with no 'module Main' header which I think is a nice compromise and could also be the default if you fire up ghci or hugs without arguments. Of course one can also import Prelude explicitly, if desired. Ben

On 27/11/06, Ian Lynagh
On Mon, Nov 20, 2006 at 12:05:46PM +0000, Malcolm Wallace wrote:
Prompted by recent discussion on the Hat mailing list about the problems of type-defaulting, I have added two new proposals for this issue to the Haskell-prime wiki at:
http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting
I don't see a proposal to remove defaulting defaulting altogether on that page - has that been discussed already?
Am I the only one who puts an explicit type signature in whenever my compiler warns me that it is having to do some defaulting? And probably 99% of those would be unnecessary if (^)'s second argument was an Int, with a genericPower (or whatever) function providing the current type signature (analogous to, for example, (!!) and genericIndex).
Defaulting is one wart I would be glad to be rid of.
Ack! Please, if anything, Int should be moved out of the Prelude and provided in a module as a useful, though usually unnecessary, form of hand-optimisation. I might be persuaded to put up with Integer being the second argument type for (^), but I'd *really* rather it remain polymorphic. Splitting up the generic list operations has always seemed like a wart in the Prelude to me. We have things like specialize pragmas now, so it seems like a solution to a problem which is no longer there. As for defaulting, if anything, I'd favour defaulting being generalised to the point where it was no longer a wart. The reason that it currently only works for numeric types is that those are the only ones where we presently have syntax which is ambiguous right off the bat, but people are talking about generalising the syntax for strings and such, so that may not always be so. I'm not yet totally convinced that this one-default-type-per-class thing will really work, it seems to me you probably are going to want something more general than that. However, it is moderately elegant, and otherwise the problem of intersecting multiple defaulting lists is an issue. On a tangentially related note, has anyone ever written something like: forM = flip mapM then forgotten to give it a type signature and tried using it from the ST monad with the monomorphism restriction on? Try the example module below. The first time I ran into it was a few iterations of GHC ago, and at the time I don't think the error message even mentioned the forM, and of course, it was a much more complicated case, and it took me a long time to track down what was happening. The MR is truly an insidious force of evil. :) --- MR.hs import Control.Monad import Control.Monad.ST import Data.STRef forM = flip mapM comp v = forM [1,2,3] $ \s -> do x <- readSTRef v writeSTRef v (x + s) main = do print $ runST (do v <- newSTRef 0 comp v readSTRef v)

On Mon, 2006-11-20 at 12:05 +0000, Malcolm Wallace wrote:
Prompted by recent discussion on the Hat mailing list about the problems of type-defaulting, I have added two new proposals for this issue to the Haskell-prime wiki at:
http://hackage.haskell.org/trac/haskell-prime/wiki/Defaulting
The main new proposal is a different way of specifying defaults, which includes the name of the class being defaulted (thus allowing user-defined classes to play this game), but unlike the original proposal, permits only one type to be specified per class. The rules are therefore also simpler, whilst still (I believe) capturing the useful cases.
BTW, just to add another use case for allowing defaulting on any class: One way to model OO class hierarchies (eg used in GUI libs like Gtk2Hs) is by having a data type and a class per-object: data Widget = ... class WidgetClass widget where toWidget :: widget -> Widget --safe upcast instance WidgetClass Widget Then each sub-type is also an instance of the class, eg a button: data Button = ... class ButtonClass button where toButton :: button -> Button instance WidgetClass Button instance ButtonClass Button etc. So Widget is the canonical instance of WidgetClass. Actually having this defaulting would be very useful. Suppose we want to load a widget from a decryption at runtime (and we do, visual builders like glade give us this). We'd have a functions like this: xmlLoad :: WidgetClass widget => FilePath -> IO (String -> widget) So the action loads up an xml file and gives us back a function which we can use to lookup named widgets from the file. Of course to make this type safe we need to do a runtime checked downcast from Widget to the specific widget type we wish to use. For example: getWidget <- xmlLoad "Foo.glade" let button1 :: Button button1 = getWidget "button1" It would be nice not to have to annotate that button1 :: Button. However often it would be necessary to do so because almost all operations on the Button type are actually generic on the ButtonClass (since there are some sub-types of Button). So actually we'd only constrain button1 to be an instance of ButtonClass. So we'd end up with ambiguous overloading - just like we get with (show . read). However if we could default it to be actually of type Button then it should all work just fine. Duncan
participants (15)
-
Ashley Yakeley
-
Benjamin Franksen
-
Bernie Pope
-
Bulat Ziganshin
-
Cale Gibbard
-
Claus Reinke
-
Duncan Coutts
-
Ian Lynagh
-
Iavor Diatchki
-
Josef Svenningsson
-
Malcolm Wallace
-
Philippa Cowderoy
-
Ross Paterson
-
Simon Marlow
-
Simon Peyton-Jones