https://wiki.haskell.org/api.php?action=feedcontributions&user=Donn&feedformat=atomHaskellWiki - User contributions [en]2022-01-20T10:55:18ZUser contributionsMediaWiki 1.27.4https://wiki.haskell.org/index.php?title=Heterogenous_collections&diff=8392Heterogenous collections2006-11-17T19:33:05Z<p>Donn: </p>
<hr />
<div>This page is a very hasty and ad-hoc summary of a common discussion on<br />
the haskell-cafe list. If you find it hard to read, please complain<br />
there and somebody hopefully will come to help.<br />
<br />
<br />
=== The problem ===<br />
<br />
Is some kind of collection of object with different types in Haskell<br />
exist? Except the tuples, which have fixed length. I find this<br />
<br />
* Tuples heterogeneous, lists homogeneous.<br />
* Tuples have a fixed length, or at least their length is encoded in their type. That is, two tuples with different lengths will have different types.<br />
* Tuples always finite.<br />
<br />
But I need something which is heterogeneous and non-fixed length. I'm<br />
used do Java, and this switch to functional languages is very strange to<br />
me. So, to be clear, I need something like LinkedList<Object> in java.<br />
<br />
<br />
=== Algebraic Datatypes ===<br />
<br />
If the number of types to cover is fixed, then I suggest a data type<br />
like<br />
<br />
<haskell><br />
data T =<br />
ConsInt Int<br />
| ConsString String<br />
| ConsChar Char<br />
</haskell><br />
<br />
or:<br />
<br />
<haskell><br />
data Object = IntObject Int | StringObject String<br />
<br />
objectString :: Object -> String<br />
objectString (IntObject v) = show v<br />
objectString (StringObject v) = v<br />
<br />
main = mapM_ (putStrLn . objectString) [(IntObject 7), (StringObject "eight")]<br />
</haskell><br />
<br />
This is a very basic solution, and often preferable. Limitations: You<br />
have to type-switch all the time if you want to do anything with the<br />
objects in the List, and the collections are clumsy to extend by new<br />
types.<br />
<br />
<br />
<br />
=== HLists, OOHaskell, Type-Level Programming ===<br />
<br />
This is the cleanest solution, but very advanced and a little<br />
restrictive. Read these two articles:<br />
<br />
* http://homepages.cwi.nl/~ralf/HList/<br />
* http://homepages.cwi.nl/~ralf/OOHaskell/<br />
<br />
There is also some related material here:<br />
<br />
* http://www.haskell.org/haskellwiki/Extensible_record<br />
<br />
<br />
=== Existential Types ===<br />
<br />
Depending on your needs and your comfort level with fancier types, the<br />
existential approach to ADTs might solve your problem. The following<br />
code is a demonstration you can cut-and-paste-and-run.<br />
<br />
This is example akin to upcasting in Java to an interface that lets<br />
you print things. That way you know how to print every object (or do<br />
whatever else it is you need to do) in the list. Beware: there is no<br />
safe downcasting (that's what Typeable would be for); that would<br />
likely be more than you need.<br />
<br />
There are other ways to do this with existentials (e.g. bounded<br />
existentials), but this is what came out of my head when I read your<br />
post. Existentials seems to be the "Haskellish" way to reduce a<br />
hetergenous list to a collection of objects with common operations.<br />
HList would be the Haskellish way for more static and flexible<br />
assurances.<br />
<br />
<haskell><br />
{-# OPTIONS -fglasgow-exts #-}<br />
<br />
module Test where<br />
<br />
data PrintPackage = forall a . PrintPackage a (a -> String)<br />
<br />
instance Show PrintPackage where<br />
show (PrintPackage val showMethod) = showMethod val<br />
<br />
list = [ PrintPackage 3 show<br />
, PrintPackage "string" show<br />
, PrintPackage 3.4 show<br />
]<br />
<br />
main = print list<br />
</haskell></div>Donn