Mutually recursive modules and google protocol-buffers

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

Mutually recursive modules and google protocol-buffers

haskell-2
I have reached an impasse in designing a Haskell API for the google's
protocol-buffers data language / format. (
http://code.google.com/apis/protocolbuffers/docs/overview.html )

The messages in protobuf are defined in a namespace that nests in the usual
hierarchical OO style that Java encourages.

To avoid namespace conflicts, I made a hierarchy of modules.

But...this is a legal pair protobuf message definitions:

> // Test that mutual recursion works.
> message TestMutualRecursionA {
>   optional TestMutualRecursionB b = 1;
>   optional int32 content = 2;
> }
>
> message TestMutualRecursionB {
>   optional TestMutualRecursionA a = 1;
>   optional int32 content = 2;
> }

And there is no way ghc can compile these in separate modules.

But the overlap of record accessors names "content" makes defining these
messages in a single module with a common namespace quite verbose.

Any opinions on the least worst way to design this?

--
Chris

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

Max Bolingbroke-2
> And there is no way ghc can compile these in separate modules.

I may be being redundant here, but you may not know that GHC actually
can compile mutually recursive modules. See
http://www.haskell.org/ghc/docs/latest/html/users_guide/separate-compilation.html#mutual-recursion
. Of course, this is not a great solution either, as creating hs-boot
files is a bit tedious, but at least the option is there.

Cheers,
Max
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

haskell-2
Ah, a teachable moment.  One of us is not entirely correct about what GHC can do
with this example.  Hopefully I am wrong, but my experiments...

Max Bolingbroke wrote:

>> And there is no way ghc can compile these in separate modules.
>
> I may be being redundant here, but you may not know that GHC actually
> can compile mutually recursive modules. See
> http://www.haskell.org/ghc/docs/latest/html/users_guide/separate-compilation.html#mutual-recursion
> . Of course, this is not a great solution either, as creating hs-boot
> files is a bit tedious, but at least the option is there.
>
> Cheers,
> Max

Consider these 3 files:

A.hs:
> module A(A) where
> import B(B)
> data A = A B

B.hs
> module B(B) where
> import A(A)
> data B = B A

Main.hs
 > module Main where
 > import A
 > import B
 > main = return ()

There is no way to create a "A.hs-boot" file that has all of
   (1) Allows A.hs-boot to be compiled without compiling B.hs first
   (2) Allows B.hs (with a {-# SOURCE #-} pragma) to be compiled after A.hs-boot
   (3) Allows A.hs to compiled after A.hs-boot with a consistent interface

But this "Main2.hs" file works fine:
> module Main where
> data A = A B
> data B = B A
> main = return ()

But in "Main2.hs" I cannot define two record field accessors such as
 > data A = A { getName :: B}
 > data B = B { getName :: A}
because there cannot be two different "getName" created in the same namespace.

There is no way GHC can put the two field accessors in different module
namespaces because their "data" types include mutual recursion.

So I can choose one of
   (*) Ignore mutual recursion and make all such .proto specifications break
   (*) Autogenerate very verbose data type names and put them all in the same
module to allow mutual recursion. And then either
       (**) Autogenerate even more verbose field accessor names
       (**) Define no field accessors and create some poor replacement, such as

> class Field'Name a b | a ->b where
>   getName :: a -> b
>   setName :: a -> b -> a



Cheers,
   Chris
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

Henning Thielemann

On Tue, 15 Jul 2008, Chris Kuklewicz wrote:

> Consider these 3 files:
>
> A.hs:
>> module A(A) where
>> import B(B)
>> data A = A B
>
> B.hs
>> module B(B) where
>> import A(A)
>> data B = B A
>
> Main.hs
>> module Main where
>> import A
>> import B
>> main = return ()


Sooner or later you want generalize your datatypes. Then you can define
    data A b = A b
   and you do not need to import B any longer. I do not know if this is a
generally applicable approach, but it helped me in some cases.
  There is still a problem with mutually recursive classes. In the one case
where I had this problem, I could solve it the opposite way, namely by
turning one type variable into a concrete type, which could represent all
values one could represent with the variable type.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

Roberto Zunino-2
In reply to this post by haskell-2
Chris Kuklewicz wrote:
> There is no way to create a "A.hs-boot" file that has all of
>   (1) Allows A.hs-boot to be compiled without compiling B.hs first
>   (2) Allows B.hs (with a {-# SOURCE #-} pragma) to be compiled after
> A.hs-boot
>   (3) Allows A.hs to compiled after A.hs-boot with a consistent interface

I thought the following A.hs-boot would suffice:

module A(A) where
data A

There's no need to provide the data constructors for type A. Does this
violate any of the goals above?

Regards,
Zun.
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

sclv
In reply to this post by haskell-2
What about generating the verbose accessor/single module code, and  
then creating a hierarchical module space as well, all importing your  
Base module, and reexporting the data types you want as well as less  
verbosely named accessor functions? Of course, this will break record  
update syntax, but maybe you could move to functional references  
instead -- given that you're generating all the code to begin with,  
autogenerating fref/lens style getter-setter pairs shouldn't be any  
more work.

--Sterl

On Jul 15, 2008, at 10:43 AM, Chris Kuklewicz wrote:

> Ah, a teachable moment.  One of us is not entirely correct about  
> what GHC can do with this example.  Hopefully I am wrong, but my  
> experiments...
>
> Max Bolingbroke wrote:
>>> And there is no way ghc can compile these in separate modules.
>> I may be being redundant here, but you may not know that GHC actually
>> can compile mutually recursive modules. See
>> http://www.haskell.org/ghc/docs/latest/html/users_guide/separate- 
>> compilation.html#mutual-recursion
>> . Of course, this is not a great solution either, as creating hs-boot
>> files is a bit tedious, but at least the option is there.
>> Cheers,
>> Max
>
> Consider these 3 files:
>
> A.hs:
>> module A(A) where
>> import B(B)
>> data A = A B
>
> B.hs
>> module B(B) where
>> import A(A)
>> data B = B A
>
> Main.hs
> > module Main where
> > import A
> > import B
> > main = return ()
>
> There is no way to create a "A.hs-boot" file that has all of
>   (1) Allows A.hs-boot to be compiled without compiling B.hs first
>   (2) Allows B.hs (with a {-# SOURCE #-} pragma) to be compiled  
> after A.hs-boot
>   (3) Allows A.hs to compiled after A.hs-boot with a consistent  
> interface
>
> But this "Main2.hs" file works fine:
>> module Main where
>> data A = A B
>> data B = B A
>> main = return ()
>
> But in "Main2.hs" I cannot define two record field accessors such as
> > data A = A { getName :: B}
> > data B = B { getName :: A}
> because there cannot be two different "getName" created in the same  
> namespace.
>
> There is no way GHC can put the two field accessors in different  
> module namespaces because their "data" types include mutual recursion.
>
> So I can choose one of
>   (*) Ignore mutual recursion and make all such .proto  
> specifications break
>   (*) Autogenerate very verbose data type names and put them all in  
> the same module to allow mutual recursion. And then either
>       (**) Autogenerate even more verbose field accessor names
>       (**) Define no field accessors and create some poor  
> replacement, such as
>
>> class Field'Name a b | a ->b where
>>   getName :: a -> b
>>   setName :: a -> b -> a
>
>
>
> Cheers,
>   Chris
> _______________________________________________
> Haskell-Cafe mailing list
> [hidden email]
> http://www.haskell.org/mailman/listinfo/haskell-cafe

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

Stuart Cook
In reply to this post by Henning Thielemann
On Wed, Jul 16, 2008 at 12:54 AM, Henning Thielemann
<[hidden email]> wrote:
> Sooner or later you want generalize your datatypes. Then you can define
>   data A b = A b
>  and you do not need to import B any longer. I do not know if this is a
> generally applicable approach, but it helped me in some cases.

This only really works if it's "natural" for A to be polymorphic in b.
Otherwise you end up with all sorts of irrelevant administrative type
parameters polluting your signatures.

(I recently had a similar problem with mutually recursive modules; I
ended up deciding to write my program in not-Haskell instead, which
made me a little sad.)


Stuart
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

John Meacham
In reply to this post by haskell-2
On Tue, Jul 15, 2008 at 12:21:16PM +0100, Chris Kuklewicz wrote:
> I have reached an impasse in designing a Haskell API for the google's
> The messages in protobuf are defined in a namespace that nests in the usual
> hierarchical OO style that Java encourages.
>
> To avoid namespace conflicts, I made a hierarchy of modules.

I wonder if this is the root of your issue, OO concepts don't map
directly to haskell concepts a lot of the time. You may end up with some
very atypical haskell code if you try to copy OO designs directly.

        John

--
John Meacham - ⑆repetae.net⑆john⑈
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

Jason Dusek
John Meacham <[hidden email]> wrote:

> Chris Kuklewicz wrote:
> > I have reached an impasse in designing a Haskell API for the
> > google's The messages in protobuf are defined in a namespace
> > that nests in the usual hierarchical OO style that Java
> > encourages.
>
> > To avoid namespace conflicts, I made a hierarchy of modules.
>
> I wonder if this is the root of your issue, OO concepts don't
> map directly to haskell concepts a lot of the time. You may
> end up with some very atypical haskell code if you try to copy
> OO designs directly.

  What do you think is a good approach to a protocol buffer
  parser generator?

--
_jsn
_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

Re: Mutually recursive modules and google protocol-buffers

haskell-2
In reply to this post by Roberto Zunino-2
Thanks Roberto!

Roberto Zunino wrote:

> Chris Kuklewicz wrote:
>> There is no way to create a "A.hs-boot" file that has all of
>>   (1) Allows A.hs-boot to be compiled without compiling B.hs first
>>   (2) Allows B.hs (with a {-# SOURCE #-} pragma) to be compiled after
>> A.hs-boot
>>   (3) Allows A.hs to compiled after A.hs-boot with a consistent interface
>
> I thought the following A.hs-boot would suffice:
>
> module A(A) where
> data A
>
> There's no need to provide the data constructors for type A. Does this
> violate any of the goals above?
>
> Regards,
> Zun.


I tried that experiment.  The failure is complicated, and triggers be a ghc bug.

Hmmm... the bug for

> module A(A) where
> data A
>   deriving Show

using "ghc -c -XGeneralizedNewtypeDeriving A.hs-boot" is

> A.hs-boot:2:0:ghc-6.8.3: panic! (the 'impossible' happened)
>   (GHC version 6.8.3 for powerpc-apple-darwin):
> newTyConEtadRhs main:A.A{tc r5z}
>
> Please report this as a GHC bug:  http://www.haskell.org/ghc/reportabug

Is this a known bug?

But now I see that

> module A(A(..)) where
> import B(B)
> data A = A B | End
>   deriving Show
>

does work.  And avoids the bug!

--
Chris

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe
Reply | Threaded
Open this post in threaded view
|

RE: Mutually recursive modules and google protocol-buffers

Sittampalam, Ganesh
Hi,

> module A(A) where
> data A
>   deriving Show

I think you should use "instance Show A" rather than "deriving Show".
All the boot file needs to do is say that the instance exists, not
explain how it is constructed.

Cheers,

Ganesh

==============================================================================
Please access the attached hyperlink for an important electronic communications disclaimer:

http://www.credit-suisse.com/legal/en/disclaimer_email_ib.html
==============================================================================

_______________________________________________
Haskell-Cafe mailing list
[hidden email]
http://www.haskell.org/mailman/listinfo/haskell-cafe