Abstract records or record interfaces? - haskell

I'm using Haskell to make a game, (this is an assignment, so don't judge me) but I'm facing a problem regarding data types.
So what I want is a data type Entity which has a location, velocity, angle and a rotation speed. A record works very well for this idea:
data Entity = Entity {
location :: Vector,
velocity :: Vector,
angle :: Float,
rotation :: Float
}
Now I want instances of Entity, namely Player Rock Pickup and Bullet. But Players Rocks and Bullets must have an extra field, namely health :: Int, and Pickup must have another extra field, namely pickupType :: PickupType.
But I have certain methods which I want to work on any Entity type. For example:
move :: Entity -> Entity
move e#(Entity {location, velocity, angle, rotation}) = e {location = location + velocity, angle = angle + rotation}
I have no idea how to do this or if this is even possible. I wouldn't understand why if it isn't possible, since this is definitely possible in other languages.
Some attempts and why they aren't quite what I desire:
Attempt 1:
type Player = Player {
e :: Entity,
health :: Int
}
This works, but it is really ugly. This, for example, is how you would move a Player:
movePlayer :: Player -> Player
movePlayer p#(e) = p {e = move e}
Which is just really ugly.
Positives:
Easy to create the abstract class.
Easy to create instances.
Easy abstract methods.
Negatives:
Hard to get or set Entity-implemented fields of an instance.
Attempt 2:
class Entity e where
getLocation :: e -> Vector
getVelocity :: e -> Vector
...
setLocation :: Vector -> e -> e
setVelocity :: Vector -> e -> e
...
data Player = Player {
playerLocation :: Vector,
playerVelocity :: Vector,
...
playerHealth :: Int
}
instance Entity Player where
getLocation = location
getVelocity = velocity
...
setLocation l e = e {location = l}
setVelocity v e = e {playerVelocity = v}
...
move :: (Entity e) => e -> e
move e = (setLocation (getLocation e + getVelocity e) . setAngle (getAngle e + getRotation e)) e
Well it works, but I hope we can all agree that their definitions are now really ugly. The abstract methods which work on any Entity also becomes way ugly. The only good thing is that methods like movePlayer become really easy.
movePlayer :: Player -> Player
movePlayer = move
I don't even need to define movePlayer anymore, since I can just use move.
Positives:
Easy to get or set Entity-implemented fields of an instance.
Negatives:
Hard to create the abstract class.
Even harder to create instances.
Hard abstract methods.
Attempt 3:
Give Entity all fields that any instance needs.
data Entity = Entity {
location :: Vector,
velocity :: Vector,
angle :: Float,
rotation :: Float,
health :: Int,
pickupType :: PickupType
}
This way I don't even need to define instances and I can just use Entity. The only problem is that you have a lot of excess data. This is currently what I use and IMO the best solution for my problem, but I still don't like it.
Positives:
Easy to create the abstract class, even though it isn't really abstract anymore.
No need to define instances.
Easy abstract methods.
Easy to get or set Entity-implemented fields of an instance.
Negatives:
A lot of unused data.
You have to define a lot of nonsense fields every time you create an Entity.
So please help me, I can't find any better methods than these three :(

I would go with your first attempt, for a very simple reason:
It accurately captures the intention of a Player - it's an Entity with additional information.
data Player = Player {
e :: Entity
health :: Int
}
While all functions dealing with may be cumbersome to write at first, you will probably never have to see them again, meaning you provided an abstract enough interface in your code not to access the state of a Player directly.
movePlayer :: Player -> Player
movePlayer p#(e) = p {e = move e}
This function is written once and then ideally you never have to deal with internals again.
Additionally, now you can use type classes as they are intended: you can abstract movePlayer in a separate type class such as Movable:
class Movable m where
move :: m -> m
-- Obviously, you can move entities
instance Movable Entity where
move e = -- stuff
But now it's really easy to move Players too:
instance Movable Player where
move (Player entity health) = Player (move entity) health
-- works, since `Entity` is movable
This aside, your type class approach has a major flaw: What about functions a Player has but an Entity doesn't? In this case you would have Player inherit Entity, like this:
class Entity e => Player e where
-- stuff ...
But since Haskell's type classes are open, anything can become a Player, which is not how it's supposed to work (unless, of course, that is your intention).

I would say that your first attempt is the way to go, for the same reasons as given in #ThreeFx's answer. I'm going to suggest a slightly different alternative though.
Given these types:
data Player = Player {
playerEntity :: Entity,
health :: Int
}
data Pickup = Pickup {
pickupEntity :: Entity,
pickupType :: PickupType
}
Instead of having a separate type class for each action that can be done on an Entity, we can provide generic higher-order functions to make it easier to perform Entity actions on Players and Pickups:
overPlayerEntity :: (Entity -> Entity) -> Player -> Player
overPlayerEntity fn (Player pe h) = Player (fn pe) h
overPickupEntity :: (Entity -> Entity) -> Pickup -> Pickup
overPickupEntity fn (Pickup pe t) = Pickup (fn pe) t
Now, we can have
movePlayer = overPlayerEntity move
movePickup = overPickupEntity move
We can also wrap this up into a type class to make it easier to write generic code as well:
class HasEntity a where
overEntity :: (Entity -> Entity) -> a -> a
instance HasEntity Player where overEntity = overPlayerEntity
instance HasEntity Pickup where overEntity = overPickupEntity
This allows things like:
move' :: HasEntity a => a -> a
move' = overEntity move
which works with both Players and Pickups. This eliminates the need for a specialized version of functions like move and at the same time we only need to write the Entity access boilerplate once.
Incidentally, this over...Entity way of doing things is approaching the "lens" technique mentioned at the end of #duplode's and #Paul Johnson's answers. These are essentially two (very) specialized lenses. If we add in the HasEntity type class it gives us what might be called a "classy lens" (this is sort of the terminology used in the lens library). You don't really need to worry about what the general lens concept means or entails, but this could give you an entry point to learn about lenses in the future.

You could just use a sum (aka "union") type.
data Entity =
Player {
location :: Vector,
-- etc.
health :: Int }
| Pickup {
location :: Vector,
-- etc.
pickupType :: PickupType}
You can factor this out by just having the sum type hold the data that varies.
This has the advantage that you can have a [Entity], which is something you can't do when all the different variations of Entity are different types (unlike OO languages).
Depending on your game model you might also want to separate the location and velocity data from the rest of the player information. Could that data be better held in some kind of spatial data structure like a quadtree? That way you can keep the constant data separate from the stuff that changes with every frame.
One thing you ought to look at are lenses, which exist to solve the problem you describe with lots of getters and setters.

This is more of a long comment than an answer, as the core of what I was going to write is covered well enough by ThreeFx's answer.
Firstly, avoid using OOP jargon, as it will lead to confusion. In your attempt #1, Entity is a data type, not a class, and it is not abstract either. The relationship between Player and Entity in attempt #1 is merely one of composition: a Player has an Entity, and it is not in any way an instance of Entity.
Secondly, record update syntax is quite ugly in Haskell. That doesn't make it complicated, just a little cumbersome. So when you say e.g. "Hard to get or set Entity-implemented fields of an instance", it is not actually hard, just not too pretty. That is not a serious enough concern to determine the design of your data types.
Thirdly, lenses are a way of (among many other things) avoiding the ugliness of the record update syntax. You probably won't want to dive into that right now (wait at least until you have finished your assignment), but I can't resist leaving a link to a highly relevant tutorial for you to read at some point in the future: Program imperatively using Haskell lenses.

Related

understanding data structure in Haskell

I have a problem with a homework (the topic is : "functional data structures").
Please understand that I don't want anyone to solve my homework.
I just have a problem with understanding the structure of this :
data Heap e t = Heap {
empty :: t e,
insert :: e -> t e -> t e,
findMin :: t e -> Maybe e,
deleteMin :: t e -> Maybe (t e),
merge :: t e -> t e -> t e,
contains :: e -> t e -> Maybe Int
}
In my understanding "empty" "insert" and so on are functions which can applied to "Heap"-type data.
Now I just want to understand how that "Heap"thing looks like.
So I was typing things like :
a = Heap 42 42
But I get errors I can't really work with.
Maybe it is a dumb question and I'm just stuck at this point for no reason, but it is killing me at the moment.
Thankful to any help
If you truly wish to understand that type, you need to understand a few requisites first.
types and values (and functions)
Firstly, you need to understand what types and values are. I'm going to assume you understand this. You understand, for example, the separation between "hello" as a value and its type, String and you understand clearly what it means when I say a = "hello" :: String and:
a :: String
a = "hello"
If you don't understand that, then you need to research values and types in Haskell. There are a myriad of books that can help here, such as this one, which I helped to author: http://happylearnhaskelltutorial.com
I'm also going to assume you understand what functions and currying are, and how to use both of them.
polymorphic types
Secondly, as your example contains type variables, you'll need to understand what they are. That is, you need to understand what polymoprhic types are. So, for example, Maybe a, or Either a b, and you'll need to understand how Maybe String is different to Maybe Int and what Num a => [a] and even things like what Num a => [Maybe a] is.
Again, there are many free or paid books that can help, the example above covers this, too.
algebraic data types
Next up is algebraic data types. This is a pretty amazingly cool feature that Haskell has. Haskell-like languages such as Elm and Idris have it as well as others like Rust, too. It lets you define your own data types. These aren't just things like Structs in other languages, and yeah, they can even contain functions.
Maybe is actually an example of an algebraic data types. If you understand these, you'll know that:
data Direction = North | South | East | West
defines a data type called Direction whose values can only be one of North, South, East or West, and you'll know that you can also use the polymorhpic type variables above to parameterise your types like so:
data Tree a = EmptyNode | Node (Tree a) (Tree a)
which uses both optionality (as in the sum type of Direction above) as well as parameterization.
In addition to this, you can also have multiple types in each value. These are called product types, and Haskell's algebraic datatypes can be expressed as a combination of Sum types that can contain Product types. For example:
type Location = (Float, Float)
data ShapeNode = StringNode Location String | CircleNode Location Float | SquareNode Location Float Float
That is, each value can be one of StringNode, CircleNode or SquareNode, and in each case there are a different set of fields given to each value. To create a StringNode, for example, you'd need to pass the values of it constructor like this: StringNode (10.0, 5.3) "A String".
Again, the freely available books will go into much more detail about these things, but we're moving in the direction of getting more than a basic understanding of Haskell now.
Finally, in order to fully understand your example, you'll need to know about...
record types
Record types are the same as product types above, except that the fields are labelled rather than being anonymous. So, you could define the shape node data type like this, instead:
type Location = (Float, Float)
data ShapeNode
= StringNode { stringLocation :: Location, stringData :: String }
| CircleNode { circleLocation :: Location, radius :: Float }
| SquareNode { squareLocation :: Location, length :: Float, height :: Float }
Each field is named, and you can't repeat the same name inside data values.
All that you need in addition to this to understand the above example is to realise your example contains all of these things together, along with the fact that you have functions as your record field values in the data type you have.
It's a good idea to thoroughly flesh out your understanding and not skip any steps, then you'll be able to follow these kinds of things much more easily in the future. :) I wish you luck!
Heap is a record with six elements. In order to create a value of that type, you must supply all six elements. Assuming that you have appropriate values and functions, you can create a value like this:
myHeap = Heap myEmpty myInsert myFindMin myDeleteMin myMerge myContains
The doesn't seem like idiomatic Haskell design, however. Why not define generic functions independent of the data, or, if they must be bundled together, a typeclass?

How to modify parts of a State in Haskell

I have a number of operations which modify a System. System is defined like this:
data System = Sys {
sysId :: Int,
sysRand :: StdGen,
sysProcesses :: ProcessDb,
sysItems :: ItemDb
}
with e.g.
type ProcessDb = M.Map Int Process
But I also have some functions, which do not need access to the full System, but have types like this:
foo' :: (Process, ItemDb) -> ((Process, ItemDb),[Event])
Currently I gave them types like
foo: System -> (System, [Event])
But this is a needlessly broad interface. To use the narrow interface above in conjuntion with System I would have to extract a single Process and the ItemDb from System, run foo' and then modify System with the results.
This is quite some unwrapping and wrapping and results in more lines of code than just passing system as a whole and let foo extract whatever it needs. In the latter case, the wrapping and unwrapping is mingled with the actual foo' operation and I have the feeling that these two aspects should be separated.
I suppose I need some kind of lifting operation which turns a narrow foo' into a foo. I suppose I could write this, but I would have to write such a lifter for every signature of the narrow functions, resulting is lots of different lifters.
is there an idiom how to solve such problems?
is it worth bothering?
One common solution is to use a class, possibly created by the Template Haskell magic of Control.Lens.TH.makeClassy. The gist is that you pass in the whole System, but you don't let the function know that that's what you're giving it. All it's allowed to know is that what you're giving it offers methods for getting and/or modifying the pieces it's supposed to handle.
I ended up writing a function which work on any State and which requires a "Lens" which captures the specfic transformation from the bigger State to the smaller State and back
focus :: (Lens s' s) -> State s' a -> State s a
focus lens ms'= do
s <- get
let (s', set) = lens s
(a, s'') = runState ms' s'
put (set s'')
return a
It allows me to write things like
run :: ExitP -> State SimState Log
...
do
evqs' <-focus onSys $ step (t,evt)
...
Where step operates on the "smaller" state
step :: Timed Event -> State Sys.System [EventQu]
Here onSys is a "Lens" and it works like this:
onSys :: Lens Sys.System SimState
onSys (Sis e s) = (s, Sis e)
where
data SimState = Sis {
events :: EventQu,
sisSys :: Sys.System
I suppose the existing Lens libraries follow a similar approach, but do much more magic, like creating lenses automatically. I did shy away from lenses. Instead I was pleased to realise that all it takes was a few lines of codes to get what I need.

What are lenses used/useful for?

I can't seem to find any explanation of what lenses are used for in practical examples. This short paragraph from the Hackage page is the closest I've found:
This modules provides a convienient way to access and update the elements of a structure. It is very similar to Data.Accessors, but a bit more generic and has fewer dependencies. I particularly like how cleanly it handles nested structures in state monads.
So, what are they used for? What benefits and disadvantages do they have over other methods? Why are they needed?
They offer a clean abstraction over data updates, and are never really "needed." They just let you reason about a problem in a different way.
In some imperative/"object-oriented" programming languages like C, you have the familiar concept of some collection of values (let's call them "structs") and ways to label each value in the collection (the labels are typically called "fields"). This leads to a definition like this:
typedef struct { /* defining a new struct type */
float x; /* field */
float y; /* field */
} Vec2;
typedef struct {
Vec2 col1; /* nested structs */
Vec2 col2;
} Mat2;
You can then create values of this newly defined type like so:
Vec2 vec = { 2.0f, 3.0f };
/* Reading the components of vec */
float foo = vec.x;
/* Writing to the components of vec */
vec.y = foo;
Mat2 mat = { vec, vec };
/* Changing a nested field in the matrix */
mat.col2.x = 4.0f;
Similarly in Haskell, we have data types:
data Vec2 =
Vec2
{ vecX :: Float
, vecY :: Float
}
data Mat2 =
Mat2
{ matCol1 :: Vec2
, matCol2 :: Vec2
}
This data type is then used like this:
let vec = Vec2 2 3
-- Reading the components of vec
foo = vecX vec
-- Creating a new vector with some component changed.
vec2 = vec { vecY = foo }
mat = Mat2 vec2 vec2
However, in Haskell, there's no easy way of changing nested fields in a data structure. This is because you need to re-create all of the wrapping objects around the value that you are changing, because Haskell values are immutable. If you have a matrix like the above in Haskell, and want to change the upper right cell in the matrix, you have to write this:
mat2 = mat { matCol2 = (matCol2 mat) { vecX = 4 } }
It works, but it looks clumsy. So, what someone came up with, is basically this: If you group two things together: the "getter" of a value (like vecX and matCol2 above) with a corresponding function that, given the data structure that the getter belongs to, can create a new data structure with that value changed, you are able to do a lot of neat stuff. For example:
data Data = Data { member :: Int }
-- The "getter" of the member variable
getMember :: Data -> Int
getMember d = member d
-- The "setter" or more accurately "updater" of the member variable
setMember :: Data -> Int -> Data
setMember d m = d { member = m }
memberLens :: (Data -> Int, Data -> Int -> Data)
memberLens = (getMember, setMember)
There are many ways of implementing lenses; for this text, let's say that a lens is like the above:
type Lens a b = (a -> b, a -> b -> a)
I.e. it is the combination of a getter and a setter for some type a which has a field of type b, so memberLens above would be a Lens Data Int. What does this let us do?
Well, let's first make two simple functions that extract the getters and setters from a lens:
getL :: Lens a b -> a -> b
getL (getter, setter) = getter
setL :: Lens a b -> a -> b -> a
setL (getter, setter) = setter
Now, we can start abstracting over stuff. Let's take the situation above again, that we want to modify a value "two stories deep." We add a data structure with another lens:
data Foo = Foo { subData :: Data }
subDataLens :: Lens Foo Data
subDataLens = (subData, \ f s -> f { subData = s }) -- short lens definition
Now, let's add a function that composes two lenses:
(#) :: Lens a b -> Lens b c -> Lens a c
(#) (getter1, setter1) (getter2, setter2) =
(getter2 . getter1, combinedSetter)
where
combinedSetter a x =
let oldInner = getter1 a
newInner = setter2 oldInner x
in setter1 a newInner
The code is kind of quickly written, but I think it's clear what it does: the getters are simply composed; you get the inner data value, and then you read its field. The setter, when it is supposed to alter some value a with the new inner field value of x, first retrieves the old inner data structure, sets its inner field, and then updates the outer data structure with the new inner data structure.
Now, let's make a function that simply increments the value of a lens:
increment :: Lens a Int -> a -> a
increment l a = setL l a (getL l a + 1)
If we have this code, it becomes clear what it does:
d = Data 3
print $ increment memberLens d -- Prints "Data 4", the inner field is updated.
Now, because we can compose lenses, we can also do this:
f = Foo (Data 5)
print $ increment (subDataLens#memberLens) f
-- Prints "Foo (Data 6)", the innermost field is updated.
What all of the lens packages do is essentially to wrap this concept of lenses - the grouping of a "setter" and a "getter," into a neat package that makes them easy to use. In a particular lens implementation, one would be able to write:
with (Foo (Data 5)) $ do
subDataLens . memberLens $= 7
So, you get very close to the C version of the code; it becomes very easy to modify nested values in a tree of data structures.
Lenses are nothing more than this: an easy way of modifying parts of some data. Because it becomes so much easier to reason about certain concepts because of them, they see a wide use in situations where you have huge sets of data structures that have to interact with one another in various ways.
For the pros and cons of lenses, see a recent question here on SO.
Lenses provide convenient ways to edit data structures, in a uniform, compositional way.
Many programs are built around the following operations:
viewing a component of a (possibly nested) data structure
updating fields of (possibly nested) data structures
Lenses provide language support for viewing and editing structures in a way that ensures your edits are consistent; that edits can be composed easily; and that the same code can be used for viewing parts of a structure, as for updating the parts of the structure.
Lenses thus make it easy to write programs from views onto structures; and from structures back on to views (and editors) for those structures. They clean up a lot of the mess of record accessors and setters.
Pierce et al. popularized lenses, e.g. in their Quotient Lenses paper, and implementations for Haskell are now widely used (e.g. fclabels and data-accessors).
For concrete use cases, consider:
graphical user interfaces, where a user is editing information in a structured way
parsers and pretty printers
compilers
synchronizing updating data structures
databases and schemas
and many other situations where you have a data structure model of the world, and a editable view onto that data.
As an additional note it is often overlooked that lenses implement a very generic notion of "field access and update". Lenses can be written for all kinds of things, including function-like objects. It requires a bit of abstract thinking to appreciate this, so let me show you an example of the power of lenses:
at :: (Eq a) => a -> Lens (a -> b) b
Using at you can actually access and manipulate functions with multiple arguments depending on earlier arguments. Just keep in mind that Lens is a category. This is a very useful idiom for locally adjusting functions or other things.
You can also access data by properties or alternate representations:
polar :: (Floating a, RealFloat a) => Lens (Complex a) (a, a)
mag :: (RealFloat a) => Lens (Complex a) a
You can go further writing lenses to access individual bands of a Fourier-transformed signal and a lot more.

How to define a class that allows uniform access to different records in Haskell?

I have two records that both have a field I want to extract for display. How do I arrange things so they can be manipulated with the same functions? Since they have different fields (in this case firstName and buildingName) that are their name fields, they each need some "adapter" code to map firstName to name. Here is what I have so far:
class Nameable a where
name :: a -> String
data Human = Human {
firstName :: String
}
data Building = Building {
buildingName :: String
}
instance Nameable Human where
name x = firstName x
instance Nameable Building where
-- I think the x is redundant here, i.e the following should work:
-- name = buildingName
name x = buildingName x
main :: IO ()
main = do
putStr $ show (map name items)
where
items :: (Nameable a) => [a]
items = [ Human{firstName = "Don"}
-- Ideally I want the next line in the array too, but that gives an
-- obvious type error at the moment.
--, Building{buildingName = "Empire State"}
]
This does not compile:
TypeTest.hs:23:14:
Couldn't match expected type `a' against inferred type `Human'
`a' is a rigid type variable bound by
the type signature for `items' at TypeTest.hs:22:23
In the expression: Human {firstName = "Don"}
In the expression: [Human {firstName = "Don"}]
In the definition of `items': items = [Human {firstName = "Don"}]
I would have expected the instance Nameable Human section would make this work. Can someone explain what I am doing wrong, and for bonus points what "concept" I am trying to get working, since I'm having trouble knowing what to search for.
This question feels similar, but I couldn't figure out the connection with my problem.
Consider the type of items:
items :: (Nameable a) => [a]
It's saying that for any Nameable type, items will give me a list of that type. It does not say that items is a list that may contain different Nameable types, as you might think. You want something like items :: [exists a. Nameable a => a], except that you'll need to introduce a wrapper type and use forall instead. (See: Existential type)
{-# LANGUAGE ExistentialQuantification #-}
data SomeNameable = forall a. Nameable a => SomeNameable a
[...]
items :: [SomeNameable]
items = [ SomeNameable $ Human {firstName = "Don"},
SomeNameable $ Building {buildingName = "Empire State"} ]
The quantifier in the data constructor of SomeNameable basically allows it to forget everything about exactly which a is used, except that it is Nameable. Therefore, you will only be allowed to use functions from the Nameable class on the elements.
To make this nicer to use, you can make an instance for the wrapper:
instance Nameable (SomeNameable a) where
name (SomeNameable x) = name x
Now you can use it like this:
Main> map name items
["Don", "Empire State"]
Everybody is reaching for either existential quantification or algebraic data types. But these are both overkill (well depending on your needs, ADTs might not be).
The first thing to note is that Haskell has no downcasting. That is, if you use the following existential:
data SomeNameable = forall a. Nameable a => SomeNameable a
then when you create an object
foo :: SomeNameable
foo = SomeNameable $ Human { firstName = "John" }
the information about which concrete type the object was made with (here Human) is forever lost. The only things we know are: it is some type a, and there is a Nameable a instance.
What is it possible to do with such a pair? Well, you can get the name of the a you have, and... that's it. That's all there is to it. In fact, there is an isomorphism. I will make a new data type so you can see how this isomorphism arises in cases when all your concrete objects have more structure than the class.
data ProtoNameable = ProtoNameable {
-- one field for each typeclass method
protoName :: String
}
instance Nameable ProtoNameable where
name = protoName
toProto :: SomeNameable -> ProtoNameable
toProto (SomeNameable x) = ProtoNameable { protoName = name x }
fromProto :: ProtoNameable -> SomeNameable
fromProto = SomeNameable
As we can see, this fancy existential type SomeNameable has the same structure and information as ProtoNameable, which is isomorphic to String, so when you are using this lofty concept SomeNameable, you're really just saying String in a convoluted way. So why not just say String?
Your items definition has exactly the same information as this definition:
items = [ "Don", "Empire State" ]
I should add a few notes about this "protoization": it is only as straightforward as this when the typeclass you are existentially quantifying over has a certain structure: namely when it looks like an OO class.
class Foo a where
method1 :: ... -> a -> ...
method2 :: ... -> a -> ...
...
That is, each method only uses a once as an argument. If you have something like Num
class Num a where
(+) :: a -> a -> a
...
which uses a in multiple argument positions, or as a result, then eliminating the existential is not as easy, but still possible. However my recommendation to do this changes from a frustration to a subtle context-dependent choice, because of the complexity and distant relationship of the two representations. However, every time I have seen existentials used in practice it is with the Foo kind of tyepclass, where it only adds needless complexity, so I quite emphatically consider it an antipattern. In most of these cases I recommend eliminating the entire class from your codebase and exclusively using the protoized type (after you give it a good name).
Also, if you do need to downcast, then existentials aren't your man. You can either use an algebraic data type, as others people have answered, or you can use Data.Dynamic (which is basically an existential over Typeable. But don't do that; a Haskell programmer resorting to Dynamic is ungentlemanlike. An ADT is the way to go, where you characterize all the possible types it could be in one place (which is necessary so that the functions that do the "downcasting" know that they handle all possible cases).
I like #hammar's answer, and you should also check out this article which provides another example.
But, you might want to think differently about your types. The boxing of Nameable into the SomeNameable data type usually makes me start thinking about whether a union type for the specific case is meaningful.
data Entity = H Human | B Building
instance Nameable Entity where ...
items = [H (Human "Don"), B (Building "Town Hall")]
I'm not sure why you want to use the same function for
getting the name of a Human and the name of a Building.
If their names are used in fundamentally different ways,
except maybe for simple things like printing them,
then you probably want two
different functions for that. The type system
will automatically guide you to choose the right function
to use in each situation.
But if having a name is something significant about the
whole purpose of your program, and a Human and a Building
are really pretty much the same thing in that respect as far as your program
is concerned, then you would define their type together:
data NameableThing =
Human { name :: String } |
Building { name :: String }
That gives you a polymorphic function name that works for
whatever particular flavor of NameableThing you happen to have,
without needing to get into type classes.
Usually you would use a type class for a different kind of situation:
if you have some kind of non-trivial operation that has the same purpose
but a different implementation for several different types.
Even then, it's often better to use some other approach instead, like
passing a function as a parameter (a "higher order function", or "HOF").
Haskell type classes are a beautiful and powerful tool, but they are totally
different than what is called a "class" in object-oriented languages,
and they are used far less often.
And I certainly don't recommend complicating your program by using an advanced
extension to Haskell like Existential Qualification just to fit into
an object-oriented design pattern.
You can try to use Existentially Quanitified types and do it like this:
data T = forall a. Nameable a => MkT a
items = [MkT (Human "bla"), MkT (Building "bla")]
I've just had a look at the code that this question is abstracting from. For this, I would recommend merging the Task and RecurringTaskDefinition types:
data Task
= Once
{ name :: String
, scheduled :: Maybe Day
, category :: TaskCategory
}
| Recurring
{ name :: String
, nextOccurrence :: Day
, frequency :: RecurFrequency
}
type ProgramData = [Task] -- don't even need a new data type for this any more
Then, the name function works just fine on either type, and the functions you were complaining about like deleteTask and deleteRecurring don't even need to exist -- you can just use the standard delete function as usual.

haskell state and typeclasses

how can i group getX and putX in a class instance ?
the code below is an answer for this post Class set method in Haskell using State-Monad
import Control.Monad.State
data Point = Point { x :: Int, y :: Int } deriving Show
getX :: State Point Int
getX = get >>= return . x
putX :: Int -> State Point ()
putX newVal = do
pt - get
put (pt { x = newVal })
increaseX :: State Point ()
increaseX = do
x - getX
putX (x + 1)
Later I hope I will implement setters and getters for a hierarchy of 2 classes, but for now i just wanna do something like this:
class A a where
putX :: Int -> State Point ()
instance A (State Point) where
putX newVal = do
pt - get
put (pt { x = newVal })
You seem to be conflating multiple concepts here, to the point that I'm not sure exactly what you're aiming to accomplish. A few thoughts on what you might be after:
Field access, i.e., a way to inspect or replace a piece of a larger data structure. This doesn't really lend itself to a type class, because for many combinations of "inner field" and "data structure" there will be more than one accessor possible. Abstractions along these lines are often called "lenses".
Stateful references in some generic fashion. For the most part in a State monad this amounts to combining something like the aforementioned lenses with the standard get and put. In this case you could have a type class for the combination of a particular monad and the accessor data type, but it wouldn't really do that much.
Overloading access to a particular field, so that functions can work on any data type that contains an "x" field. In this case I assume you'd also want "y", as some sort of type class for 2D points. This is entirely separate from the above issues, however.
Perhaps you could clarify your goal?

Resources