Say, I want to define a record Attribute like this:
data Attribute = Attribute {name :: String, value :: Any}
This is not valid haskell code of course. But is there a type 'Any' which basically say any type will do? Or is to use type variable the only way?
data Attribute a = Attribute {name :: String, value :: a}
In Haskell, every statement is considered as a mathematical expression and the category of this expression is called as a Type. You can say that "Type" is the data type of the expression used at compile time. To learn more about the Type, we will use the ":t" command.
Haskell also incorporates polymorphic types---types that are universally quantified in some way over all types. Polymorphic type expressions essentially describe families of types. For example, (forall a)[a] is the family of types consisting of, for every type a, the type of lists of a.
Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.
Types are infered using a process generally called unification. Haskell belongs to the Hindley-Milner family, which is the unification algorithm it uses to determine the type of an expression. If unification fails, then the expression is a type error.
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.
Adding to bdonlan's answer: Instead of GADTs, you can also use existential types:
{-# LANGUAGE ExistentialQuantification #-}
class Foo a where
foo :: a -> a
data AnyFoo = forall a. Foo a => AnyFoo a
instance Foo AnyFoo where
foo (AnyFoo a) = AnyFoo $ foo a
mapFoo :: [AnyFoo] -> [AnyFoo]
mapFoo = map foo
This is basically equivalent to bdonlan's GADT solution, but doesn't impose the choice of data structure on you - you can use a Map
instead of a list, for example:
import qualified Data.Map as M
mFoo :: M.Map String AnyFoo
mFoo = M.fromList [("a", AnyFoo SomeFoo), ("b", AnyFoo SomeBar)]
The data AnyFoo = forall a. Foo a => AnyFoo a
bit can also be written in GADT notation as:
data AnyFoo where
AnyFoo :: Foo a => a -> AnyFoo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With