[Haskell-cafe] Splitting data and function declarations over multiple files

Job Vranish jvranish at gmail.com
Thu Oct 1 11:35:43 EDT 2009


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 at 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 at gmail.com> wrote:
>
>> On Wed, Sep 30, 2009 at 9:54 AM, Peter Verswyvelen <bugfact at 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 at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20091001/bf88ca03/attachment.html


More information about the Haskell-Cafe mailing list