I'm not sure this is really necessary (at least syntax-wise). We can do something like:
data T a class Trait a where { trait :: T a -> Int }
instance Trait Int where { trait _ = 0 } instance Trait Char where { trait _ = 1 }
As far as I can tell with the various --ddump-* flags, the compiler hasn't yet figured out that the argument to trait is useless (i.e., it keeps it in there). However, from a sanity point of view, I much prefer to write my "useless arguments" like this; that way at least *I* know that they'll never be evaluated. I suppose the only thing that could go wrong is someone writing:
instance Foo Bool where { trait x = x `seq` 1 }
in which case it would be wrong for the compiler to get rid of this argument. I suppose that your solution gets rid of this problem by relizing that seq doesn't have absent demand on its argument (quite the opposite, in fact). Of course, the powers that be can weight in on this, and I'm sure that you're aware of the phantom type solution, but I figured I'd post anyway so that others can get a look at types like this for their own benefit... -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume
-----Original Message----- From: haskell-admin@haskell.org [mailto:haskell-admin@haskell.org] On Behalf Of Andrew J Bromage Sent: Tuesday, June 24, 2003 9:18 PM To: haskell@haskell.org Subject: Language extension proposal
G'day all.
I've been toying with an idea for a small language extension, and I was curious what you all think of this.
As a motivating example, consider the following standard typeclass:
class Bounded a where min :: a max :: a
This is an example of what I refer to as a "traits typeclass" (by analogy to traits classes, well-known to C++ programmers). The idea is that you want to specify certain properties/operations which depend on a _type_, rather than any particular value of that type.
Another example is floating point format information, like the information in C's <float.h>. One might implement this as:
class (Bounded a) => FloatTraits a where epsilon :: a -- OK mantissaDigits :: Int -- Not OK!
For obvious reasons, the declaration of mantissaDigits is not valid Haskell. Instead, you might do something like this:
class FloatTraits a where mantissaDigits :: a -> Int
instance FloatTraits Float where mantissaDigits _ = 24
instance FloatTraits Double where mantissaDigits _ = 53
and invoke it as, say:
mantissaDigits (undefined :: Float)
A decent strictness analyser can tell if an argument to some function is always unused (in GHC core terminology, this means its demand is "absent") and thus avoid passing the argument at all. However, it is currently impossible to tell if this is true all instances of a typeclass. What I would like is some annotation that I can use to tell my compiler that this argument of this method is always unused, no matter what instance it resolves to.
My proposal is to grab a new punctuation symbol (I will use '~' as an example) to sit alongside the GHC extension use of '!'. Where '!' means that an argument may be evaluated before calling a function, '~' means than an argument may be ignored by the callee. So in the above example, I can write:
class FloatTraits a where mantissaDigits :: ~a -> Int
Now this marker is not as simple to implement as '!'. The strict marker is advisory; if you stripped all '!'s from your program, it would still have the same static semantics. Not so with '~', which must be statically checked.
However, the static analysis is pretty trivial, except for the problem of inference. Basically, if a variable has absent demand, it a) can't be pattern matched on (unless the pattern is a variable, of course), and b) can't be passed as an argument to a function (including a data constructor) which doesn't also treat that argument as having absent demand.
I therefore propose that the marker not be inferred for top-level definitions, or at least for exported definitions. If you declare it, it's checked, but otherwise it's not. In addition, any calls that you pass a variable with absent demand to must themselves have the marker declared explicitly in their type signatures.
There may also be an argument for extending '~' to data constructors, in the same way that H98 uses '!'. This would allow parameters with absent demand to be stored in data structures. I can't think of a use for this right now, but it shouldn't be too much harder to add.
What do you all think? Useful? Not worth the effort?
Cheers, Andrew Bromage _______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
G'day all. On Wed, Jun 25, 2003 at 08:48:12AM -0700, Hal Daume wrote:
I'm not sure this is really necessary (at least syntax-wise).
Well, of course, no extension is absolutely necessary in a Turing-hard language. :-) For the record, here are a couple of other solutions which avoid the problem. You could, for example, make the return type a phantom type: newtype T a = T Int class Trait a where { trait :: T a } instance Trait Int where { trait = T 0 } instance Trait Char where { trait = T 1 } Or construct the type dictionary explicitly: data Traits a = Traits { trait1 :: a, trait2 :: Int } class Trait a where traits :: Traits a instance Trait Char where traits = Traits { trait1 = 'a', trait2 = 16 } Neither solution seems as nice, though, particularly as the traits typeclass idiom is already entrenched (e.g. Bounded).
As far as I can tell with the various --ddump-* flags, the compiler hasn't yet figured out that the argument to trait is useless (i.e., it keeps it in there).
Nor can it, because you could easily declare an instance in another module for which the argument is _not_ useless. This is impossible to detect at compile time.
Of course, the powers that be can weight in on this, and I'm sure that you're aware of the phantom type solution, but I figured I'd post anyway so that others can get a look at types like this for their own benefit...
Sure. Any input is good. I'm not convinced that my proposed solution is the best one. (I'm pretty sure that it's the minimal extension required, though.) Cheers, Andrew Bromage
participants (2)
-
Andrew J Bromage -
Hal Daume