Extension and parameterized classes

Dear Haskell experts, I working on a large Haskell project on Model Based Testing (see https://github.com/TorXakis/TorXakis) and I would like to get feedback on a design issue I have related to extension and parameterized classes. I will describe a small simplified example to illustrate the issue and I appreciate any feedback. I have a class that extends another class as follows: class Base a => Extend a where -- | Constructor from Base fromBase :: Base b => b -> a I can define an instance of Extend that hides the Base implementation as follows: {-# LANGUAGE ExistentialQuantification #-} data BaseHidden = forall a . Base a => BaseHidden { _base :: a , ... -- additional extension info } instance Extend BaseHidden where fromBase b = BaseHidden b ... -- additional extension initialization I can define a parameterized data class of which the parameter is the type of the Base class as follows: data BaseExpose a = BaseExpose { _base :: a , ... -- additional extension info } With this parameterized data class, I can make the following fromBase' function fromBase' :: Base a => a -> BaseExpose a fromBase' a = BaseExpose a ... -- additional extension initialization My question is can I make BaseExpose an instance of Extend? I am aware that the signature of fromBase states that for all 'b' of Base an Extend of type 'a' must be able to be made. Yet, in my case 'a' is a parameterized class 'BaseExpose x' and since the type of Extend is provided (it is a constructor) I think it is acceptable that 'BaseExpose b' is returned as type. I have looked at some extensions, such as InstanceSigs, yet I found no solution. Does anybody on this mailing list have an answer or solution for me? Also experience in a large project related to maintenance for the two alternatives (hiding or exposing types) is appreciated! Thanks in advance, Pierre van de Laar ________________________________ The information contained in this message may be confidential and legally protected under applicable law. The message is intended solely for the addressee(s). If you are not the intended recipient, you are hereby notified that any use, forwarding, dissemination, or reproduction of this message is strictly prohibited and may be unlawful. If you are not the intended recipient, please contact the sender by return e-mail and destroy all copies of the original message.

Hi!
I am aware that the signature of fromBase states that for all 'b' of Base an Extend of type 'a' must be able to be made. Yet, in my case 'a' is a parameterized class 'BaseExpose x' and since the type of Extend is provided (it is a constructor) I think it is acceptable that 'BaseExpose b' is returned as type.
I'm afraid I'm agreeing with the compiler here. When you instantiate this class class Base a => Extend a where fromBase :: Base b => b -> a so that `a` is `BaseExpose x`, then you need to implement fromBase :: Base b => b -> BaseExpose x and your fromBase' has a less general type fromBase' :: Base x => x -> BaseExpose x and that's it. It's the same issue as when you try to typecheck `id :: a -> b`. If it type-checked, you could write (pure) crashing type-correct code. I don't have enough data, but I guess you don't need `fromBase` at all. if `a` is `Base`, then it's also `Extend`, as long as you implement any extra operations. You don't need to coerce it to `Extend` with `fromBase`. BTW, as opposed to object oriented programmers, I think most of us doesn't use the class system for encapsulation, but the module system instead (with all its limitations). If the module system is not enough for you and you are ready for the bleeding edge, the Backpack may have what you need. Having said that, I think we usually err on the side of exposing too much, with all the simplicity and testing ease benefits it provides, rather than on the side of hiding too much. The user of a library is free to encapsulate more strongly in his import lists or by defining an interface module. Only the user knows his use case.

Yes, and a large part of this being that hiding stuff tends to come back
and bite you when you need the internals anyway at some point. This leads
to .Internals modules and such in the end, sometimes retrofitted when the
need is realized.
On Thu, Feb 14, 2019 at 8:15 AM Mikolaj Konarski
Hi!
I am aware that the signature of fromBase states that for all 'b' of Base an Extend of type 'a' must be able to be made. Yet, in my case 'a' is a parameterized class 'BaseExpose x' and since the type of Extend is provided (it is a constructor) I think it is acceptable that 'BaseExpose b' is returned as type.
I'm afraid I'm agreeing with the compiler here. When you instantiate this class
class Base a => Extend a where fromBase :: Base b => b -> a
so that `a` is `BaseExpose x`, then you need to implement
fromBase :: Base b => b -> BaseExpose x
and your fromBase' has a less general type
fromBase' :: Base x => x -> BaseExpose x
and that's it. It's the same issue as when you try to typecheck `id :: a -> b`. If it type-checked, you could write (pure) crashing type-correct code.
I don't have enough data, but I guess you don't need `fromBase` at all. if `a` is `Base`, then it's also `Extend`, as long as you implement any extra operations. You don't need to coerce it to `Extend` with `fromBase`.
BTW, as opposed to object oriented programmers, I think most of us doesn't use the class system for encapsulation, but the module system instead (with all its limitations). If the module system is not enough for you and you are ready for the bleeding edge, the Backpack may have what you need. Having said that, I think we usually err on the side of exposing too much, with all the simplicity and testing ease benefits it provides, rather than on the side of hiding too much. The user of a library is free to encapsulate more strongly in his import lists or by defining an interface module. Only the user knows his use case. _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
-- brandon s allbery kf8nh allbery.b@gmail.com
participants (3)
-
Brandon Allbery
-
Mikolaj Konarski
-
Pierre_van_der_Laar (Functional Account)