20

I like to put type signatures for all top-level definitions in my code. However, type signatures in instance declarations don't seem to be allowed, and if I put one I get a "Misplaced type signature" error from GHC. Why is this so? Why can't GHC check if the type signature is the same as what it was expecting, and reject (or warn) if it isn't?

Prateek
  • 2,377
  • 17
  • 29
  • 4
    On [the ticket I opened](http://hackage.haskell.org/trac/ghc/ticket/5676) SPJ commented: "I've wanted [type signatures in instance declarations] myself, so I've done it in a spare moment." He currently set the milestone to GHC 7.6, though there is a slight chance it will make it into GHC 7.4. Thanks for asking this question! And thanks, Daniel Fischer, for suggesting that we make a ticket. – Dan Burton Dec 05 '11 at 20:28

6 Answers6

14

You can add type signatures for instances using [the new] -XInstanceSigs, which is especially useful for bringing type variables in scope. You can find more information in the official docs.

crockeea
  • 21,651
  • 10
  • 48
  • 101
13

Most of the other answers here are pretty old... there's now a language extension:

stick the following at the top of your file:

{-# Language InstanceSigs #-}
JonnyRaa
  • 7,559
  • 6
  • 45
  • 49
12

You can create the functions separately, outside the instance body, if you really want the type declarations.

class Class a where
    f1 :: a -> a

instance Class Foo where
    f1 = foo_f1

--monomorphic version of f1 for Foo:
foo_f1 :: Foo -> Foo
foo_f1 = ...
hugomg
  • 68,213
  • 24
  • 160
  • 246
5

Since the signature is part of the class definition, a type signature in an instance declaration would be a duplicate signature. I don't think there's a problem with allowing duplicate signatures in principle, but there's no advantage in allowing them generally, and it's simpler to disallow them. So the language definition says there can be at most one type signature per entity. The feature of allowing signatures also in instance declarations hasn't been asked for much, so there's no extension allowing it. If you really want that, you can raise a feature request on the GHC trac. If it gets enough interest, it may be implemented (but I don't expect the demand to be high).

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • 1
    The advantage will be that GHC will check the signature - the programmer can assert his/her belief of the type signature and have it checked, and caught in case it is wrong. – Prateek Dec 03 '11 at 12:30
  • 1
    @Prateek The compiler checks it against the signature in the class anyway. Since any signature except the one from the class definition (with the pertinent type variables substituted for the instance types) must be rejected, it can give no additional information or safety. It would only be a bit of additional documentation for readers of the code (that isn't a bad thing, but you can achieve it now with signatures in comments - I do that if I think the types aren't obvious and well-known). – Daniel Fischer Dec 03 '11 at 12:51
  • 4
    I meant checking against what the programmer believes the signature to be (apart from checking against the signature in the class). This does not give any additional safety, true. But it can give more understandable error messages: "you think the type signature is X, but actually it is Y" instead of some other type error. Also, it allows a programmer to adopt a uniform style of writing type declarations, instead of having to make a special case of commenting it out inside instance declarations. – Prateek Dec 03 '11 at 13:38
  • @Prateek I don't understand, surely the programmer believes that the most general type of the implementation is at least as general as what the class specifies? Can you give an example of an error message that would be better if a direct signature would be used than with the inherited? I can't think of such a case off the top of my head. However, if the implementation is not short, it's good practice to do what missingno suggested, define a top level function and bind the class member to that in the instance declaration, why not do that also for short implementations? – Daniel Fischer Dec 03 '11 at 14:01
  • I agree that uniformity in writing type signatures is nice, and for that it would be handy to allow signatures in instance declarations. But I find it not to be a pressing problem. – Daniel Fischer Dec 03 '11 at 14:04
  • 6
    Programmers can make mistakes too. :-) For example, a programmer might mistakenly think that to make something some `T` a `Functor` one has to define `fmap :: T (a -> b) -> T a -> T b` (getting confused with `Applicative`) and write this type signature, along with some complicated implementation of `fmap`. Surely a "This type signature is wrong, it should be such-and-such!" error will be easier to understand than whatever "could not match bar with foo, expected baz, actual quux" error that will be generated. – Prateek Dec 03 '11 at 14:11
  • 3
    I agree that this is not a major issue, since there is no safety being violated, it's more an issue of clearer communication between the user and the compiler and being able to adopt a uniform coding style. As for the extra top-level function, that seems a bit inelegant : it introduces a needless name in the top-level namespace (which need not be exported in case it's a module, I agree), it separates the implementation from the instance declaration, it needs extra work and attention, ... – Prateek Dec 03 '11 at 14:14
  • 3
    We've been talking a little about this on #haskell IRC. I made a ticket: http://hackage.haskell.org/trac/ghc/ticket/5676 – Dan Burton Dec 03 '11 at 23:30
  • 2
    @DanBurton Too slow, Prateek filed a request hours ago :) – Daniel Fischer Dec 04 '11 at 00:09
  • @DanielFischer yep, looks like SPJ just tagged them as dupes of each other. Is there a way to merge tickets? – Dan Burton Dec 04 '11 at 00:17
  • @Prateek, I know this is old, but I figured I should mention that there are quite a few cases where one ends up wanting the extra top-level function anyway. In particular, that approach seems to work better if you're going to introduce GHC rewrite rules that match on the function in question. – dfeuer Sep 07 '16 at 14:20
2

In any case, the type is redundant and one normally wants to avoid redundancies. In Frege, it is nevertheless allowed to write type signatures for instance members. They are checked and then thrown away. It's of course easier to forbid them right away.

Ingo
  • 36,037
  • 5
  • 53
  • 100
0

Allowing type signatures in instance declarations is enabled by default since GHC 9.2.1.

This follows from GHC 9.2.1 supporting GHC2021, which enables some extensions by default, among these the InstanceSigs extension.

Here's an example from the documentation:

instance Eq a => Eq (T a) where
   (==) :: forall b. b -> b -> Bool
   (==) x y = True

Note that type signatures in instances are redundant in most cases. The documentation mentions these possible motivations for adding them:

  • using the type checker to confirm that the inferred type matches what the programmer expects (this is the motivation the user posting the original question gives)

  • as a way to document the code

  • bringing scoped type variables into scope


On the history of allowing type signatures in instance declarations in Haskell

This feature has its origins in this StackOverflow question.

The user posting the question created an issue ticket the same he asked the question in 2011. The day after, Dan Burton also created a ticket, and the first ticket was closed as a duplicate. Another day later Simon Peyton Jones chimed in and mentioned him having wanted this possibility himself. He sketched out the implementation the same day and made the commit seven days later. The extension was added to GHC 7.6. It was enabled by default in GHC 9.2.1, which was released in October 2021.

Note: PureScript added the extension in 2017.

Carl
  • 937
  • 10
  • 21