
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
On Wed, Sep 30, 2009 at 9:54 AM, Peter Verswyvelen
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