Note that there are some explanatory texts on larger screens.

plurals
  1. POHaskell polymorphic functions with records and class types
    primarykey
    data
    text
    <p>this post is the following of <a href="https://stackoverflow.com/questions/7430520/oo-like-interface-implementation-in-haskell">this one.</a></p> <p>I'm realizing a simple battle system as toy project, the typical system you can find in games like Final Fantasy et simila. I've solved the notorious "Namespace Pollution" problem with a class type + custom instances. For example:</p> <pre><code>type HitPoints = Integer type ManaPoints = Integer data Status = Sleep | Poison | .. --Omitted data Element = Fire | ... --Omitted class Targetable a where name :: a -&gt; String level :: a -&gt; Int hp :: a -&gt; HitPoints mp :: a -&gt; ManaPoints status :: a -&gt; Maybe [Status] data Monster = Monster{monsterName :: String, monsterLevel :: Int, monsterHp :: HitPoints, monsterMp :: ManaPoints, monsterElemType :: Maybe Element, monsterStatus :: Maybe [Status]} deriving (Eq, Read) instance Targetable Monster where name = monsterName level = monsterLevel hp = monsterHp mp = monsterMp status = monsterStatus data Player = Player{playerName :: String, playerLevel :: Int, playerHp :: HitPoints, playerMp :: ManaPoints, playerStatus :: Maybe [Status]} deriving (Show, Read) instance Targetable Player where name = playerName level = playerLevel hp = playerHp mp = playerMp status = playerStatus </code></pre> <p>Now the problem: I have a spell type, and a spell can deal damage or inflict a status (like Poison, Sleep, Confusion, etc):</p> <pre><code>--Essentially the result of a spell cast data SpellEffect = Damage HitPoints ManaPoints | Inflict [Status] deriving (Show) --Essentially a magic data Spell = Spell{spellName :: String, spellCost :: Integer, spellElem :: Maybe Element, spellEffect :: SpellEffect} deriving (Show) --For example fire = Spell "Fire" 20 (Just Fire) (Damage 100 0) frogSong = Spell "Frog Song" 30 Nothing (Inflict [Frog, Sleep]) </code></pre> <p>As suggested in the linked topic, I've created a generic "cast" function like this:</p> <pre><code>--cast function cast :: (Targetable t) =&gt; Spell -&gt; t -&gt; t cast s t = case spellEffect s of Damage hp mana -&gt; t Inflict statList -&gt; t </code></pre> <p>As you can see the return type is t, here showed just for consistency. I want be able to return a new targetable (i.e. a Monster or a Player) with some field value altered (for example a new Monster with less hp, or with a new status). The problem is that i can't just to the following:</p> <pre><code>--cast function cast :: (Targetable t) =&gt; Spell -&gt; t -&gt; t cast s t = case spellEffect s of Damage hp' mana' -&gt; t {hp = hp', mana = mana'} Inflict statList -&gt; t {status = statList} </code></pre> <p>because hp, mana and status "are not valid record selector". The problem is that I don't know a priori if t will be a monster or a player, and I don't want to specify "monsterHp" or "playerHp", I want to write a pretty generic function. I know that Haskell Records are clumsy and not much extensibile...</p> <p>Any idea?</p> <p>Bye and happy coding,</p> <p>Alfredo </p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload