| ... | ... | @@ -14,7 +14,7 @@ Problems with the current defaulting rule: |
|
|
|
|
|
|
|
- Defaults are limited to Prelude numeric classes. A tool like Hat, which transforms Haskell source, cannot transform the defaults, because there is no way make defaults apply to the transformed classes rather than the original ones.
|
|
|
|
|
|
|
|
- Defaults cannot be applied to user-defined classes. It would be nice for some applications to be able to allow a default clause to name the class being defaulted over, as well as the type to choose. Examples include QuickCheck?, where you might wish to default the Arbitrary class to something small (e.g. Bool) when a value is otherwise unconstrained.
|
|
|
|
- Defaults cannot be applied to user-defined classes. It would be nice for some applications to be able to allow a default clause to name the class being defaulted over, as well as the type to choose. Examples include QuickCheck, where you might wish to default the `Arbitrary` class to something small (e.g. `Bool`) when a value is otherwise unconstrained.
|
|
|
|
|
|
|
|
- Report specification of defaulting is impossible to implement in the presence of recursive modules. (Should it be specified that a group of mutually recursive modules must have exactly the same defaulting?)
|
|
|
|
|
| ... | ... | @@ -25,7 +25,7 @@ Problems with the current defaulting rule: |
|
|
|
- Against import/export: a change in the imports of a module might silently change behavior
|
|
|
|
- A compromise might be to allow defaults which will be inherited to be specified only in the module that defines a class, but groups of mutually recursive modules may override defaulting locally. this will avoid the import changing behavior problem and allow some sort of inheritence of defaults.
|
|
|
|
|
|
|
|
## Proposal 1
|
|
|
|
## Proposal 1 - name the class
|
|
|
|
|
|
|
|
|
|
|
|
|
| ... | ... | @@ -85,7 +85,7 @@ default D (Double,String,Int,()) |
|
|
|
- might hide errors, an optional warning on defaulting should be possible.
|
|
|
|
- not clear how to choose a single unambiguous member of more than one list of types
|
|
|
|
|
|
|
|
## Proposal 2
|
|
|
|
## Proposal 2 - name the class + no lists
|
|
|
|
|
|
|
|
|
|
|
|
|
| ... | ... | @@ -94,7 +94,7 @@ Possible syntax, by analogy with instance decls: |
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
topdecl -> default tycls type
|
|
|
|
topdecl -> default tycls type
|
|
|
|
```
|
|
|
|
|
|
|
|
|
| ... | ... | @@ -108,12 +108,20 @@ default C T |
|
|
|
|
|
|
|
|
|
|
|
the type 'a', constrained by class 'C' but otherwise unresolved, is instantiated to the sole type 'T'.
|
|
|
|
If there is no unique choice, for instance because more than one class-with-a-default is mentioned in the context (and their default types are different), then it is a static error. Note that it is OK to have several classes in the context of the defaultable value, provided only one of them is declared to yield a default type, or if more
|
|
|
|
than one yields a type, those types are the same. Choosing a default after context simplification means that no conflicts between super- and sub-classes can arise.
|
|
|
|
|
|
|
|
|
|
|
|
- If there is no unique choice, for instance because more than one class-with-a-default is mentioned in the context (and their default types are different), then it is a static error.
|
|
|
|
- Note that it is OK to have several classes in the context of the defaultable value,
|
|
|
|
|
|
|
|
Some examples:
|
|
|
|
- provided only one of them is declared to yield a default type,
|
|
|
|
- or if more than one yields a type, those types are the same.
|
|
|
|
- Choosing a default after context simplification means that no conflicts between super- and sub-classes can arise.
|
|
|
|
|
|
|
|
### Examples
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Here are some examples, to clarify the idea:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
| ... | ... | @@ -164,26 +172,60 @@ Default is Int, same as above, except for the extra constraint Show a. There is |
|
|
|
A static error, because there are no defaults declared for any of the classes involved.
|
|
|
|
|
|
|
|
|
|
|
|
### Backwards compatibility
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The current Haskell'98 default-default behaviour can be specified as:
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
default ( Num => Integer
|
|
|
|
, Real => Integer
|
|
|
|
, Enum => Integer
|
|
|
|
, Integral => Integer
|
|
|
|
, Fractional => Double
|
|
|
|
, RealFrac => Double
|
|
|
|
, Floating => Double
|
|
|
|
, RealFloat => Double
|
|
|
|
)
|
|
|
|
default Num Integer
|
|
|
|
default Real Integer
|
|
|
|
default Enum Integer
|
|
|
|
default Integral Integer
|
|
|
|
default Fractional Double
|
|
|
|
default RealFrac Double
|
|
|
|
default Floating Double
|
|
|
|
default RealFloat Double
|
|
|
|
```
|
|
|
|
|
|
|
|
### Turning off defaults
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
In Haskell'98, the default decl not only declares a new default type for some classes, but can also implicitly remove defaults for other classes (at the same time!).
|
|
|
|
Whilst `default ()` switches off all defaulting, `default (Int)` changes the default type for the Num, Real, Enum, Integral classes, and also declares there is no
|
|
|
|
default for the Fractional, RealFrac, Floating, and RealFloat classes (by virtue of Int's failure to be a instance of those).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Under the current proposal, there is no explicit means to turn off defaults. A minor modification rectifies this shortcoming - simply permit the omission of the *type* part of the default decl. An omitted type indicates there is no default type for this class.
|
|
|
|
|
|
|
|
|
|
|
|
### Multi-parameter type classes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Defaulting for MPTC follows the scheme for single-parameter classes.
|
|
|
|
|
|
|
|
|
|
|
|
```wiki
|
|
|
|
topdecl -> default tycls type_1 type_2 ... type_n
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
That is, there is a single unique relation between types that can be chosen if *all* of its variables are otherwise unconstrained.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Open questions: if some of the variables are already resolved to actual types, is it OK to default the remaining variables? Assuming the resolved types are in the default relation anyway? What if the already-resolved types are not in the default relation? Would anyone ever want to use defaulting to choose different types depending on what other types have already beeen resolved?
|
|
|
|
|
|
|
|
|
|
|
|
### Pros
|
|
|
|
|
|
|
|
|
|
|
|
- less ad hoc than current method
|
|
|
|
- simpler, more general, and less ad hoc than current method
|
|
|
|
- overcomes the Hat transformation problem
|
|
|
|
- does not rely on textual ordering of decl
|
|
|
|
- permits defaulting of user-defined classes, not just Prelude ones
|
| ... | ... | @@ -193,7 +235,7 @@ default ( Num => Integer |
|
|
|
|
|
|
|
- not sure if this exactly captures the existing Haskell'98 module (but because defaults are currently limited to Prelude classes, it probably does).
|
|
|
|
|
|
|
|
## Proposal 3
|
|
|
|
## Proposal 3 - global scope
|
|
|
|
|
|
|
|
|
|
|
|
|
| ... | ... | |