Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to avoid ugly code resolving this problem in Haskell (LANGUAGE extentions)?
    text
    copied!<p>I'm trying to write a program that simulates several creatures in a world. Basically the word sends a message over a list of creatures, and each creature gives his response, which in turn modifies the world.</p> <p>I simplified what I'm trying to write in the following skeleton:</p> <pre><code>module Structure0 where type Message = String class Creature a where processInput :: a -&gt; Message -&gt; Message class World a where processAction :: a -&gt; b -&gt; Message -&gt; a getCreatures :: a -&gt; [b] ---- USAGE EXAMPLE ---- data Parrot = Parrot Int deriving Show instance Creature Parrot where processInput p s = s data ParrotWorld = ParrotWorld [Parrot] instance World ParrotWorld where processAction w p s = w getCreatures (ParrotWorld ps) = ps </code></pre> <p>In this code, I would that the parameter b in World class definition could assume all the data value that belong to the Creature class, something like:</p> <pre><code>processAction :: (Creature b) =&gt; a -&gt; b -&gt; Message -&gt; a </code></pre> <p>Of course this examples aren't actual haskell code, lo let's pass illustrating two solution i found: the first, involving ExistentialQuantification:</p> <pre><code>{-# LANGUAGE ExistentialQuantification #-} module Structure1 where type Message = String class Creature_ a where processInput :: a -&gt; Message -&gt; Message data Creature = forall c. Creature_ c =&gt; Creature c instance Creature_ Creature where processInput (Creature c) = processInput c class World a where processAction :: a -&gt; Creature -&gt; Message -&gt; a getCreatures :: a -&gt; [Creature] ---- USAGE EXAMPLE ---- data Parrot = Parrot Int deriving Show instance Creature_ Parrot where processInput u s = s data ParrotWorld = ParrotWorld [Creature] instance World ParrotWorld where processAction w p s = w getCreatures (ParrotWorld ps) = ps </code></pre> <p>and the second, suggested by a kind guy on #haskell, using TypeFamilies:</p> <pre><code>{-# LANGUAGE TypeFamilies, FlexibleContexts #-} module Structure2 where type Message = String class Creature a where processInput :: a -&gt; Message -&gt; Message class (Creature (WorldCreature a)) =&gt; World a where type WorldCreature a :: * processAction :: a -&gt; WorldCreature a -&gt; Message -&gt; a getCreatures :: a -&gt; [WorldCreature a] ---- USAGE EXAMPLE ---- data Parrot = Parrot Int deriving Show instance Creature Parrot where processInput p s = s data ParrotWorld = ParrotWorld [Parrot] instance World ParrotWorld where type WorldCreature ParrotWorld = Parrot processAction w p s = w getCreatures (ParrotWorld ps) = ps </code></pre> <p>The main objective of this exercise is writing nice, elegant code. So, the questions:</p> <p>1) Should I express Creature as a Class instead of a Data? (I'm doing this because a Creature is just a thing that implement the processInput function, and the many actual Creature implementations vary a lot; expecially during prototyping, I'd like not to change constantly the way in which a Creature pattern-matches.</p> <p>2) The first solution I provide it's a bit ugly due to the boilerplate of maintaing both Creature and Creature_ versions. It has the benefit, however, that I can write mixed list of type [Creature]; Problem is that I can't pattern match against an object, id est things like:</p> <pre><code>\(Creature (Parrot x)) -&gt; x </code></pre> <p>will fail due to type system. Can I make this all right?</p> <p>3) The second solution has a problem of extendibility: say I would to construct a World with two types of creatures, say Parrot1 and Parrot2: how could I write the code in that case?</p> <p>4) Am I structuring the code from a wrong point of view? Can I get an elegant solution just using plain haskell?</p> <p>Thank you all :)</p> <p>Carlo</p>
 

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