[Haskell] method annotations

John Meacham john at repetae.net
Wed Mar 7 22:22:12 EST 2007

On Sat, Mar 03, 2007 at 08:23:08AM -0500, Isaac Dupree wrote:
> Unfortunately it would be difficult for the compiler to know that no-one
> is going to make an instance that does depend on its argument (as long
> as it does not do full-program analysis to determine the layout of data
> structures). Maybe there should be some sort of annotation on class
> method arguments that are supposed to be ignored, even if only a pragma,
> if it would help compilers figure this out.

indeed, I have given this some thought too, but not just for whether a
type will be unused. my current thinking is something like

> class Bits a where
>         shift :: a -> !Int -> a
> class Eq a where
>         (==) :: a -> a -> !Bool
> class Typeable a where
>         getType :: ~a -> TypeRep

where '!Int' means that the class is strict in the Int argument. and ~
means it is unused. 

note, these are not just hints, but actually affect the class

shift as above would translate to something ilke

> shift :: BitsDict a -> Int -> a 
> shift bd x i = i `seq` shiftInstance bd x i

where shiftInstance selects the appropriate value from the dictionary

of course, the real benefit is now that we can do unboxing on class

we can treat the above class declaration as if it were

class Bits a where
        shift :: a -> Int# -> a

safely and rewrite instance declarations appropriately

likewise, the ! on the return value in Eq means that we should unbox it.
(this is actually always safe, so perhaps a pragma will do for this,
"UNPACK" seems appropriate)

for the other case

> class Typeable a where
>         getType :: ~a -> TypeRep

would create a method like so

> getType :: TypeableDict a -> a -> TypeRep
> getType td a = getTypeInstance td (undefined `asTypeOf` a)

which causes getType to always throw away its argument, allowing the
compiler to make assumptions based on it.

another implicit optimization that is going on in my translations above is
eta-expansion of the class methods (which is independent of the
optimizations given above). this is potentially unsafe, but I have been
performing the optimization in jhc without ill effect and with noticable
benefit. however, you can specify the "NOETA" pragma in order to
suppress this auto-eta-expansion as it does decrease sharing.

another option for controlling eta expansion would be something like

class Eq a where
        (==) :: a -> !(a -> Bool)

which makes explicit that the partial result of (==) applied to one
argument could usefully be shared.

currently, these optimization are availabe in jhc, but only via pragmas
and some built in heuristics/special knowledge in the compiler. 
Implementing the above syntax has been on my todo list. Anecdotal
examination of core leads me to believe they could be signifigantly


John Meacham - ⑆repetae.net⑆john⑈

More information about the Haskell mailing list