Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell - List of instances of a Typeclass

I'm fairly new to Haskell, and to get better I'm trying to make a simple web server. I wanted to make how I represent pages extendable, so my idea was to make webpages be a list of Renderable data (like how you can make a list of objects that implement a certain interface in Java) where Renderable is

class Renderable a where
    render :: a -> IO String

Unfortunately I learned that lists MUST be a concrete type, so I can only make a list of one type of Renderable data. Also it seems impossible to create data that is constrained by a typeclass, so I can't make something like RenderList data. My temporary solution has been like this:

myPage =
    [render $ someData
    ,render $ someMoreData
    ,render $ someOtherData
    ...
    ]

but this feels awkward, makes the use of a typeclass have no benefit, and feels like there should be a better way. So I'm wondering what ways could I restructure what I have to be cleaner, more in line with standard Haskell practices, and still be easily extendable?

Thanks.

like image 622
Terrance Niechciol Avatar asked Oct 08 '12 00:10

Terrance Niechciol


People also ask

Are Haskell lists homogeneous?

Lists in Haskell must be type-homogeneous.

How are lists defined in Haskell?

In Haskell, lists are a homogenous data structure. It stores several elements of the same type. That means that we can have a list of integers or a list of characters but we can't have a list that has a few integers and then a few characters. And now, a list!

What are Typeclasses in Haskell?

What's a typeclass in Haskell? A typeclass defines a set of methods that is shared across multiple types. For a type to belong to a typeclass, it needs to implement the methods of that typeclass. These implementations are ad-hoc: methods can have different implementations for different types.


1 Answers

You're trying to implement an object-oriented style of design. In Java, for example, you'd have a List<Renderable> and you'd be all set. This design style is a little bit less natural in Haskell; you need to create a wrapper type for a bounded existential as demonstrated on the Haskell wiki page for existential types. For example:

class Renderable_ a where
  render :: a -> IO String

data Renderable = forall a. Renderable_ a => Renderable a
instance Renderable_ Renderable where
  render (Renderable a) = render a

You can then have a list of Renderable, which you can render however you like. Like I said, though, that is sort of an OO style which is less natural in Haskell. You can probably avoid this by rethinking your data structures. You say that you "wanted to make how you represent pages extendable"; consider other ways of doing that instead.

Unrelated: I'm guessing render doesn't need to produce an IO String action. Try to keep IO out of the core of your design, if you can.

like image 183
mergeconflict Avatar answered Nov 07 '22 15:11

mergeconflict