Along the projection/co-algebra lines (I actually didn't know that's what they were called until today :)  yay for learning new things!)

How about something like this:

-- Define "prototypes" for your class of actions here
data Actor = Actor {pos::Vector2 Float, move::Vector2 Float -> Actor}

-- simple class that selects your actions based on type
class ActorClass a where
  mkActor :: a -> Actor

-- object types
data Ball = Ball ...  -- stuff
data Paddle = Paddle ... -- stuff
data Wall = Wall ... -- suff

-- Functions for working with objects
getBallPosition (Ball ...) = ...
getPaddlePosition (Paddle ...) = ...

moveBall (Ball ...) = ...
movePaddle (Ball ...) = ...

-- selection actions for Ball
instance Actor Ball where
  mkActor this = let
    pos' = getBallPosition this
    move' v = moveBall this
    in Actor pos' move'

-- selection actions for Paddle    
instance Actor Paddle where
  mkActor this = let
    pos' = getPaddlePosition this
    move' v = movePaddle this
    in Actor pos' move'


Base off a technique I ran across here:
http://www.mail-archive.com/haskell@haskell.org/msg04513.html

Also, a useful wikipage for doing OO things in haskell:
http://www.haskell.org/haskellwiki/OOP_vs_type_classes

- Job


On Thu, Oct 1, 2009 at 4:45 AM, Peter Verswyvelen <bugfact@gmail.com> wrote:
I'm not sure if I understand what you mean with this co-algebraic approach, but I guess you mean that functions - like move - don't work directly on any datatype; you need to provide other functions that give access to the data. But that's basically what type classes do no? And that's also related to my earlier post of "strong duck typing" in Haskell. 

At least also in C#, that's the way I usually write code that works on any type, just make an interface or pass in a delegate.  I also know that my OO background keeps pushing me in the wrong direction when it comes to Haskell ;-) 

The collision handling approach is always interesting :)  In OO this is usually solved using multi-methods or visitors: http://en.wikipedia.org/wiki/Multiple_dispatch. What I usually did in old games of mine to handle collisions is not look at the type, but at the "collision specific features" of a type (which are again functions that extract information from the object), and that is most likely again the co-algebraic approach?

On Wed, Sep 30, 2009 at 9:15 PM, Luke Palmer <lrpalmer@gmail.com> wrote:
On Wed, Sep 30, 2009 at 9:54 AM, Peter Verswyvelen <bugfact@gmail.com> wrote:
> I guess this is related to the expression problem.
> Suppose I have a datatype
> data Actor = Ball ... | Paddle ... | Wall ...
> and a function
> move (Ball ...) =
> move (Paddle ...) =
> move (Wall ...) =
> in Haskell one must put Actor and move into a single file.
> This is rather cumbersome if you work with multiple people or want to keep
> the files small and readable.
> Surely it is possible to use type classes, existentials, etc to split the
> data type into multiple ones, but that's already advanced stuff in a sense.

You can do it without type classes and existentials.  The
functionality you want is already supported by Haskell, you just have
to let go of your syntactical expectations.  The trick is that you
should rewrite your data type not as an algebra (a set of
constructors), but as a coalgebra (a set of projections).

Let's say your two open functions are:

move :: Actor -> Actor
isAlive :: Actor -> Bool

This gives rise to the definition of an Actor type:

data Actor = Actor { move :: Actor, isAlive :: Bool }

And then the alternatives of your open data type are just values of type Actor:

ball :: Vector -> Vector -> Actor
ball pos vel = Actor {
   move = ball (pos + vel) vel,
   isAlive = True
 }

etc.

This trick works well until you get to the encoding of functions that
pattern match on multiple Actors at the same time.  As far as I can
tell, that cannot be encoded in this style in any reasonable way.
Such functions must be rephrased in a coalgebraic style; i.e. instead
of asking about constructors, using projection functions it knows are
available.

So for example instead of implementing "collide" by asking about
pairs, add functions which report a shape function and a normal, or
whatever your collide algorithm needs from shapes.

You would probably end up having to do this anyway even with your
proposed extension, because watch:

partial data Actor = Ball ...

collide (Ball ...) (Ball ...) = ...
collide (Ball ...) x = ...

We don't know about any other constructors, so the second line has to
contain a pattern-free x.  So you would have to use projection
functions to get any information about it, exactly as you would when
you're writing in the coalgebraic style.

So, Yes!  Haskell can do that!

Luke


_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe