[Haskell-cafe] modelling problem

J. Garrett Morris trevion at gmail.com
Fri Dec 8 11:19:03 EST 2006


On 12/8/06, Kurt Schelfthout <kurt.schelfthout at gmail.com> wrote:
> 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.


More information about the Haskell-Cafe mailing list