Why can't I use the type `Show a => [Something -> a]`?

haskell

Solution

The type signature doesn't say what you think it says.

This seems to be a common misunderstanding. Consider the function

foo :: Show a => Rec -> a

People frequently seem to think this means that "`foo` can return any type that it wants to, so long as that type supports `Show`". It doesn't.

What it actually means is that `foo` must be able to return any possible type, because the caller gets to choose what the return type should be.

A few moments' thought will reveal that `foo` actually cannot exist. There is no way to turn a `Rec` into any possible type that can ever exist. It can't be done.

People often try to do something like `Show a => [a]` to mean "a list of mixed types but they all have `Show`". That obviously doesn't work; this type actually means that the list elements can be any type, but they still have to be all the same.

What you're trying to do seems reasonable enough. Unfortunately, I think your first example is about as close as you can get. You could try using tuples and lenses to get around this. You could try using Template Haskell instead. But unless you've got a hell of a lot of fields, it's probably not even worth the effort.

Problem

I have a record type say ``` data Rec { recNumber :: Int , recName :: String -- more fields of various types } ``` And I want to write a `toString` function for Rec : ``` recToString :: Rec -> String recToString r = intercalate "\t" $ map ($ r) fields where fields = [show . recNumber, show . recName] ``` This works. `fields` has type `[Rec -> String]`. But I'm lazy and I would prefer writing ``` recToString r = intercalate "\t" $ map (\f -> show $ f r) fields where fields = [recNumber, recName] ``` But this doesn't work. Intuitively I would say `fields` has type `Show a => [Rec -> a]` and this should be ok. But Haskell doesn't allow it. I'd like to understand what is going on here. Would I be right if I said that in the first case I get a list of functions such that the 2 instances of show are actually not the same function, but Haskell is able to determine which is which at compile time (which is why it's ok). ``` [show . recNumber, show . recName] ^-- This is show in instance Show Number ^-- This is show in instance Show String ``` Whereas in the second case, I only have one literal use of `show` in the code, and that would have to refer to multiple instances, not determined at compile time ? ``` map (\f -> show $ f r) fields ^-- Must be both instances at the same time ``` Can someone help me understand this ? And also are there workarounds or type system expansions that allow this ?

Original source