
On 12/8/06, Kurt Schelfthout
Hi Haskell'ers, <snip>
class Activity a c where start :: c -> a -> Time --start of the activity (this isn't actually dependent on c, I guess) end :: c -> a -> Time --end of the activity delta :: a -> Time -> c -> c --how the constituent is changed at the given time <snip> How can I now represent the state of the simulation (i.e. all activites on all constituents). E.g. a list of activities won't do since the list is heterogeneous (i.e. [Paint Ball White, Move Ball (2,0)]) I know about existentials, but I'm at a loss at how to implement the "wrapper" datatype that is exemplified on http://www.haskell.org/hawiki/ExistentialTypes since my class has two parameters, in fact I'm at a loss at how to use existentials here completely.
An existential type will do roughly what you want. I prefer GADT syntax here: data AnyActivity where AnyActivity :: Activity a c => a -> c -> AnyActivity Then, given an activity/constituent pair like, say, Move (2,0) and Ball, you can say: AnyActivity (Move (2,0)) Ball to package the pair. The resulting object has type AnyActivity, and can be stored in a list with other AnyActivities. You can write variations on your class methods that work on the packaged datatype: startAny :: AnyActivity -> Time startAny (AnyActivity a c) = start c a endAny :: AnyActivity -> Time endAny (AnyActivity a c) = end c a deltaAny :: AnyActivity -> Time -> AnyActivity deltaAny (AnyActivity a c) time = AnyActivity a (delta a time c)
Then, how could I go back from the "general" lists (or whatever datatype) of [a]'s and [c]'s, to a list of [([a],c)] of all activities a that are applicable to a certain constituent c? I can't seem to be able to use the Typeable class for example, since this can not "cast" to typeclasses, only to concrete types (I think...).
I'm not exactly sure what you want here. Since activities of a different type can affect the same constituent, it's not possible to go from a constituent c to a list of activities. You could, for example, find all the AnyActivity wrappers that contain a given constituent, if you added Typeable and Eq constraints: -- I didn't actually test this code data AnyActivity where AnyActivity :: (Activity a c, Typeable c, Eq c) => a -> c -> AnyActivity activitiesAffecting :: (Eq c, Typeable c) => c -> [AnyActivity] -> [AnyActivity] activitiesAffecting c [] = [] activitiesAffecting c (a@(AnyActivity _ c'):as) | c `eq` c' = a : activitiesAffecting c as | otherwise = activitiesAffecting c as where t `eq` t' | Just t'' <- cast t' = t == t'' | otherwise = False Extracting the original a and c used in a wrapper can be done as well, if you also include a Typeable constraint on a.
More straightforward ways of modelling this problem (avoiding multiple type class parameters and existentials :) )are also welcome.
Without seeing more of your goals, I'm not sure I can suggest anything else. I've found myself writing wrapper code like this before, and it doesn't have to end up completely confused and unusuable. On the other hand, it does feel somewhat inelegant to me - looking at FRP, for instance, might give you some good ideas for other approaches. /g -- It is myself I have never met, whose face is pasted on the underside of my mind.