Philip Holzenspies | 29 Aug 13:01 2012
Picon

Why is Bag's Data instance "broken"?

Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this
function was never applied. The source of Bag's instance of the Data class seems to explain why:

instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"

Is there a rationale to not allow gunfolds and to keep toConstr abstract? More to the point for my needs, is
there a reason to not allow dataCast1 casting of Bags?

Regards,
Philip
José Pedro Magalhães | 29 Aug 13:11 2012
Picon

Re: Why is Bag's Data instance "broken"?

Hi Philip,

On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"


Is there a rationale to not allow gunfolds and to keep toConstr abstract?

As far as I understand, this is to keep `Bag` itself abstract, preventing users from inspecting its internals.
 
More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

That is a separate issue; I believe this instance is just missing a `dataCast1 = gcast1` line.
All datatypes of kind `* -> *` should have such a definition.

(Having a look at Data.Data, I guess the same applies to `Ptr a` and `ForeignPtr a`.
And `Array a b` seems to be missing the `dataCast2` method. I propose fixing all of these.)


Cheers,
Pedro
 

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Edward Kmett | 29 Aug 19:10 2012
Picon

Re: Why is Bag's Data instance "broken"?

I've been meaning to put in a proposal to replace the Data instances for Map, etc. with one that pretends there is a fake 'fromList' constructor that restores the invariants. 


In my experience this works much better than just making everyone who relies on Data randomly crash, and it preserves the invariants of the opaque structure.

I use this approach on many of my own container types.

-Edward

On Wed, Aug 29, 2012 at 7:11 AM, José Pedro Magalhães <jpm <at> cs.uu.nl> wrote:
Hi Philip,

On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"


Is there a rationale to not allow gunfolds and to keep toConstr abstract?

As far as I understand, this is to keep `Bag` itself abstract, preventing users from inspecting its internals.
 
More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

That is a separate issue; I believe this instance is just missing a `dataCast1 = gcast1` line.
All datatypes of kind `* -> *` should have such a definition.

(Having a look at Data.Data, I guess the same applies to `Ptr a` and `ForeignPtr a`.
And `Array a b` seems to be missing the `dataCast2` method. I propose fixing all of these.)


Cheers,
Pedro
 

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Edward Kmett | 20 Sep 13:19 2012
Picon

Re: Why is Bag's Data instance "broken"?

Note: It was probably built with an eye towards how Data.Map and the like performed abstraction. However, This isn't necessary to protect the invariants of a bag. 


The constructors exposed via Data do not have to be the actual constructors of the data type. With this you can quotient out the portions of the structure you don't want the user to be able to inspect.

See the libraries <at> proposal that I put in 3-4 weeks ago (which will have just passed) to fix all the broken Data instances for containers by using virtual constructors such as 'fromList', (which incidentally led to Milan finding huge space and time improvements in fromList).

Effectively allowing the user to use the 'listToBag' as a "constructor" loses no information violates no invariants, and prevents code written for uniplate, SYB, etc. from having to crash, panic or give up upon the sight of a mkNoRepType.

My reaction for years to the sight of a mkNoRepType and undefined gunfold has been to hang my head. Now I just fix them.

-Edward

On Wed, Aug 29, 2012 at 7:11 AM, José Pedro Magalhães <jpm <at> cs.uu.nl> wrote:
Hi Philip,

On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"


Is there a rationale to not allow gunfolds and to keep toConstr abstract?

As far as I understand, this is to keep `Bag` itself abstract, preventing users from inspecting its internals.
 
More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

That is a separate issue; I believe this instance is just missing a `dataCast1 = gcast1` line.
All datatypes of kind `* -> *` should have such a definition.

(Having a look at Data.Data, I guess the same applies to `Ptr a` and `ForeignPtr a`.
And `Array a b` seems to be missing the `dataCast2` method. I propose fixing all of these.)


Cheers,
Pedro
 

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
José Pedro Magalhães | 20 Sep 13:22 2012
Picon

Re: Why is Bag's Data instance "broken"?

Right now I was just planning to fix the missing dataCast1 from Bag, and the rest from
Data.Data (see http://hackage.haskell.org/trac/ghc/ticket/7256). I think those are just
a bug, unrelated to the abstraction story, no?


Cheers,
Pedro

On Thu, Sep 20, 2012 at 12:19 PM, Edward Kmett <ekmett <at> gmail.com> wrote:
Note: It was probably built with an eye towards how Data.Map and the like performed abstraction. However, This isn't necessary to protect the invariants of a bag. 

The constructors exposed via Data do not have to be the actual constructors of the data type. With this you can quotient out the portions of the structure you don't want the user to be able to inspect.

See the libraries <at> proposal that I put in 3-4 weeks ago (which will have just passed) to fix all the broken Data instances for containers by using virtual constructors such as 'fromList', (which incidentally led to Milan finding huge space and time improvements in fromList).

Effectively allowing the user to use the 'listToBag' as a "constructor" loses no information violates no invariants, and prevents code written for uniplate, SYB, etc. from having to crash, panic or give up upon the sight of a mkNoRepType.

My reaction for years to the sight of a mkNoRepType and undefined gunfold has been to hang my head. Now I just fix them.

-Edward

On Wed, Aug 29, 2012 at 7:11 AM, José Pedro Magalhães <jpm <at> cs.uu.nl> wrote:
Hi Philip,

On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"


Is there a rationale to not allow gunfolds and to keep toConstr abstract?

As far as I understand, this is to keep `Bag` itself abstract, preventing users from inspecting its internals.
 
More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

That is a separate issue; I believe this instance is just missing a `dataCast1 = gcast1` line.
All datatypes of kind `* -> *` should have such a definition.

(Having a look at Data.Data, I guess the same applies to `Ptr a` and `ForeignPtr a`.
And `Array a b` seems to be missing the `dataCast2` method. I propose fixing all of these.)


Cheers,
Pedro
 

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users



_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Edward Kmett | 20 Sep 15:24 2012
Picon

Re: Why is Bag's Data instance "broken"?

The missing dataCast1 is just a bug, yes. I suppose someone who uses Bag and cares can submit something about fixing gunfold.

On Thu, Sep 20, 2012 at 7:22 AM, José Pedro Magalhães <jpm <at> cs.uu.nl> wrote:
Right now I was just planning to fix the missing dataCast1 from Bag, and the rest from
Data.Data (see http://hackage.haskell.org/trac/ghc/ticket/7256). I think those are just
a bug, unrelated to the abstraction story, no?


Cheers,
Pedro


On Thu, Sep 20, 2012 at 12:19 PM, Edward Kmett <ekmett <at> gmail.com> wrote:
Note: It was probably built with an eye towards how Data.Map and the like performed abstraction. However, This isn't necessary to protect the invariants of a bag. 

The constructors exposed via Data do not have to be the actual constructors of the data type. With this you can quotient out the portions of the structure you don't want the user to be able to inspect.

See the libraries <at> proposal that I put in 3-4 weeks ago (which will have just passed) to fix all the broken Data instances for containers by using virtual constructors such as 'fromList', (which incidentally led to Milan finding huge space and time improvements in fromList).

Effectively allowing the user to use the 'listToBag' as a "constructor" loses no information violates no invariants, and prevents code written for uniplate, SYB, etc. from having to crash, panic or give up upon the sight of a mkNoRepType.

My reaction for years to the sight of a mkNoRepType and undefined gunfold has been to hang my head. Now I just fix them.

-Edward

On Wed, Aug 29, 2012 at 7:11 AM, José Pedro Magalhães <jpm <at> cs.uu.nl> wrote:
Hi Philip,

On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"


Is there a rationale to not allow gunfolds and to keep toConstr abstract?

As far as I understand, this is to keep `Bag` itself abstract, preventing users from inspecting its internals.
 
More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

That is a separate issue; I believe this instance is just missing a `dataCast1 = gcast1` line.
All datatypes of kind `* -> *` should have such a definition.

(Having a look at Data.Data, I guess the same applies to `Ptr a` and `ForeignPtr a`.
And `Array a b` seems to be missing the `dataCast2` method. I propose fixing all of these.)


Cheers,
Pedro
 

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users


_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users




_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
José Pedro Magalhães | 20 Sep 10:40 2012
Picon

Re: Why is Bag's Data instance "broken"?



On Wed, Aug 29, 2012 at 12:01 PM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
Dear GHCers,

I'm performing traversals over GHC-API results (HsSyn et al). For this purpose, I'm using SYB generics.

I found that I couldn't use "ext1Q" for a function with type "Data x => Bag x -> String", i.e. that this function was never applied. The source of Bag's instance of the Data class seems to explain why:


instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"

Btw, where is this instance defined?


Thanks,
Pedro
 


Is there a rationale to not allow gunfolds and to keep toConstr abstract? More to the point for my needs, is there a reason to not allow dataCast1 casting of Bags?

Regards,
Philip
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Philip Holzenspies | 20 Sep 12:12 2012
Picon

Re: Why is Bag's Data instance "broken"?

On 20 Sep 2012, at 09:40, José Pedro Magalhães wrote:

instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"

Btw, where is this instance defined?

GHCROOT/compiler/utils/Bag.lhs, lines 266-270 (current git-repo HEAD and many versions previously).

Ph.
_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
José Pedro Magalhães | 21 Sep 10:04 2012
Picon

Re: Why is Bag's Data instance "broken"?

I've now added a dataCast1 method to this instance in HEAD; casting should now work as expected.


Cheers,
Pedro

On Thu, Sep 20, 2012 at 11:12 AM, Philip Holzenspies <pkfh <at> st-andrews.ac.uk> wrote:
On 20 Sep 2012, at 09:40, José Pedro Magalhães wrote:

instance Data a => Data (Bag a) where
  gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
  toConstr _   = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
  gunfold _ _  = error "gunfold"
  dataTypeOf _ = mkNoRepType "Bag"

Btw, where is this instance defined?

GHCROOT/compiler/utils/Bag.lhs, lines 266-270 (current git-repo HEAD and many versions previously).

Ph.

_______________________________________________
Glasgow-haskell-users mailing list
Glasgow-haskell-users <at> haskell.org
http://www.haskell.org/mailman/listinfo/glasgow-haskell-users

Gmane