Question about using FlexibleInstances

I am new to Haskell. One quirk I have come across is that if I want to implement a Show instance for an arbitrary function, I am told by the compiler that I need to enable the FlexibleInstances pragma, and the relaxation there indeed fixes my code, which looks like this:

instance Show (a -> ()) where
  show a = "OK"

The use case is not really important; a dead-simple “test runner” function which computes some assertions in a do block and finishes with a pure ().

My question is: How would I write the above (presumably using a newtype?) such that it wouldn’t require the pragma?

I guess with a newtype it would look like

newtype Func a = Func (a -> ())

instance Show (Func a) where
  show _ = "OK"

then you’d have to convert a -> () to Func a to use the Show instance

1 Like

Let’s explain first why you need FlexibleInstances:

  • Haskell 2010 requires instance heads to be of the form T a1 a2 ..., where T is a type constructor, and the a1 a2 ... are zero or more type variables.
  • In your example, you’ve written the outermost type constructor (->) infix; a is a type variable ok; () is a type constructor, not a variable.
  • It’s an unusual (and fairly daft) situation for a function type to produce a result type (). So more realistic use cases would also have a type var in that position. (That’s why your binding for show can only produce a string literal.)

FlexibleInstances of itself is not a ‘dangerous’ extension. But with FlexibleInstances you can write OverlappingInstances; and those need great care.

Is there any reason your instance couldn’t look like this (which doesn’t need FlexibleInstances)?

instance Show (a -> b) where
  show _ = "Ok"
1 Like

The compiler is probably giving you bad advice here. I suspect the solution to your problem lies elsewhere. Could you share a small code sample that demonstrates the problem?

1 Like

Thanks, for anyone else coming across FlexibleInstances for the first time, this is the clearest answer IMO.

As I mentioned, this code isn’t doing anything useful or important, and this was really just a way for me to learn more how type constructors work with different signatures. I am coming from a Rust background so this is super helpful!