Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Typeclass Inspection

I would like to use haskell to implement a game, and would like to use a system of type classes to implement the item system. It would work something like this:

data Wood = Wood Int

instance Item Wood where
  image a = "wood.png"
  displayName a = "Wood"

instance Flammable Wood where
  burn (Wood health) | health' <= 0 = Ash
                     | otherwise    = Wood health'
      where health' = health - 100

where the Item and Flammable classes are something like this:

class Item a where
  image :: a -> String
  displayName :: a -> String

class Flammable a where
  burn :: (Item b) => a -> b

To do this, I would need a way to detect whether a value is an instance of a type class.

The Data.Data module gives a similar functionality so that leads me to believe that this is possible.

like image 674
adrusi Avatar asked Feb 05 '12 16:02

adrusi


People also ask

What is a Haskell Typeclass?

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.

How does deriving work in Haskell?

The second line, deriving (Eq, Show) , is called the deriving clause; it specifies that we want the compiler to automatically generate instances of the Eq and Show classes for our Pair type. The Haskell Report defines a handful of classes for which instances can be automatically generated.

What is instance Haskell?

An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.


1 Answers

Type classes are probably the wrong way to go here. Consider using plain algebraic data types instead, for example:

data Item = Wood Int | Ash

image Wood = "wood.png"
image Ash = ...

displayName Wood = "Wood"
displayName Ash = "Ash"

burn :: Item -> Maybe Item
burn (Wood health) | health' <= 0 = Just Ash
                   | otherwise    = Just (Wood health')
  where health' = health - 100
burn _ = Nothing -- Not flammable

If this makes it too hard to add new items, you can instead encode the operations in the data type itself.

data Item = Item { image :: String, displayName :: String, burn :: Maybe Item }

ash :: Item
ash = Item { image = "...", displayName = "Ash", burn :: Nothing }

wood :: Int -> Item
wood health = Item { image = "wood.png", displayName = "Wood", burn = Just burned }
    where burned | health' <= 0 = ash
                 | otherwise    = wood health'
          health' = health - 100

However, this makes it harder to add new functions. The problem of doing both at the same time is known as the expression problem. There is a nice lecture on Channel 9 by Dr. Ralf Lämmel where he explains this problem more in depth and discusses various non-solutions, well worth the watch if you have time.

There are approaches to solving it, but they are considerably more complex than the two designs I've illustrated, so I recommend using one of those if it fits your needs, and not worrying about the expression problem unless you have to.

like image 176
hammar Avatar answered Sep 23 '22 18:09

hammar