
Matthew Brecknell
Since the concrete type has been forgotten, there's no way to get it back. You can't write a function that exposes the forgotten type, so getConnection is basically a lost cause. When you write "getConnection :: Transaction c", you are saying that the function is fully polymorphic in c. In other words, you are allowing the caller of getConnection to specify the type of connection. But you can't do that, because you already gave the connection a concrete type when you constructed the TransactionT. You might think you could get away with "getConnection :: Connection c => Transaction c", but this is still too polymorphic.
So what can you do? You can pattern-match on a TransactionT, provided you don't allow the existentially-quantified type to escape the scope of the pattern-match. In this case, all you know is that the type conforms to the Connection class, so you must use methods from the Connection class within that scope to consume the quantified type.
Thanks, using pattern matching to avoid mentioning the type didn't even cross my mind. You are correct in assuming that I thought I could get away with "getConnection :: Connection c => Transaction c". To be honest, I still don't understand why it's too polymorphic. To me it says that it'll return a Transaction parameterised by a type confirming to the Connection interface, even though the concrete type is long lost.