Generally speaking, Any
types aren’t very useful. Consider: If you make a polymorphic list that can hold anything, what can you do with the types in the list? The answer, of course, is nothing – you have no guarantee that there is any operation common to these elements.
What one will typically do is either:
-
Use GADTs to make a list that can contain elements of a specific typeclass, as in:
data FooWrap where FooWrap :: Foo a => a -> FooWrap type FooList = [FooWrap]
With this approach, you don’t know the concrete type of the elements, but you know they can be manipulated using elements of the
Foo
typeclass. -
Create a type to switch between specific concrete types contained in the list:
data FooElem = ElemFoo Foo | ElemBar Bar type FooList = [FooElem]
This can be combined with approach 1 to create a list that can hold elements that are of one of a fixed set of typeclasses.
-
In some cases, it can be helpful to build a list of manipulation functions:
type FooList = [Int -> IO ()]
This is useful for things like event notification systems. At the time of adding an element to the list, you bind it up in a function that performs whatever manipulation you’ll later want to do.
-
Use
Data.Dynamic
(not recommended!) as a cheat. However, this provides no guarantee that a specific element can be manipulated at all, and so the above approaches should be preferred.