Splitting data and function declarations over multiple files

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. But wouldn't it be possible to allow these to be put into multiple files, and let the compiler merge them back into one? A bit like C#'s partial keyword: in file Ball.hs: *partial data Actor = Ball ...* *move (Ball ...) =* in Paddle.hs *partial data Actor = Paddle ...* *move (Paddle ...) =* The compiler would then merge all partial data types and functions into one. As far as no overlap exists in the pattern matches in move, so that the order of the pattern matches does not matter at all, the partial trick should be possible no? Cheers, Peter

Hi Peter,
sounds to me you want to have a look at "Open Data Types and Open
Functions" by Andres Löh and Ralf Hinze:
http://people.cs.uu.nl/andres/OpenDatatypes.pdf
Cheers,
/Niklas
On Wed, Sep 30, 2009 at 5:54 PM, Peter Verswyvelen
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. But wouldn't it be possible to allow these to be put into multiple files, and let the compiler merge them back into one? A bit like C#'s partial keyword: in file Ball.hs: partial data Actor = Ball ... move (Ball ...) = in Paddle.hs partial data Actor = Paddle ... move (Paddle ...) = The compiler would then merge all partial data types and functions into one. As far as no overlap exists in the pattern matches in move, so that the order of the pattern matches does not matter at all, the partial trick should be possible no? Cheers, Peter
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Wed, Sep 30, 2009 at 8:54 AM, Peter Verswyvelen
I guess this is related to the expression problem.
Actually, this is exactly 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.
Yes, and type classes are the current solution. I think the most elegant solution right now is provided by Data Types a la Carte; see http://www.cse.chalmers.se/~wouter/publications.html
But wouldn't it be possible to allow these to be put into multiple files, and let the compiler merge them back into one? A bit like C#'s partial keyword:
in file Ball.hs: *partial data Actor = Ball ...* *move (Ball ...) =*
in Paddle.hs *partial data Actor = Paddle ...* *move (Paddle ...) =*
The compiler would then merge all partial data types and functions into one.
As far as no overlap exists in the pattern matches in move, so that the order of the pattern matches does not matter at all, the partial trick should be possible no?
Yes, that's true. There's some good reading about this proposal here: http://www.haskell.org/haskellwiki/Extensible_datatypes -- ryan

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

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

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

Opps, errors, it should be more like:
moveBall (Vector2 x y) (Ball ...) = ...
movePaddle (Vector2 x y) (Paddle ...) = ...
-- selection actions for Ball
instance Actor Ball where
mkActor this = let
pos' = getBallPosition this
move' v = mkActor $ moveBall v this
in Actor pos' move'
-- selection actions for Paddle
instance Actor Paddle where
mkActor this = let
pos' = getPaddlePosition this
move' v = mkActor $ movePaddle v this
in Actor pos' move'
Hmm, I bet some generics, or template haskell could clean up the extra
boilerplate associated with this technique.
- Job
On Thu, Oct 1, 2009 at 11:35 AM, Job Vranish
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
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
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
On Wed, Sep 30, 2009 at 9:54 AM, Peter Verswyvelen
wrote: 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

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.
Just a nitpick: you don't have to put Actor and move into the same module. module A where data Actor = Ball | Paddle | Wall module B where import A (Actor) move Ball = ... move Paddle = ... move Wall = ... But that's probably not what you meant. Regards, apfelmus -- http://apfelmus.nfshost.com
participants (6)
-
Heinrich Apfelmus
-
Job Vranish
-
Luke Palmer
-
Niklas Broberg
-
Peter Verswyvelen
-
Ryan Ingram