
Hello, all. Is it possible to import all types except some of instances and to re-defined hiding instances, so resulting (new) module will be the same types, mostly the same instances, but some of instances will be replaced? I tried to import all hiding interesting type, then to import interesting type without instances, but when I redefine its instances I get error about duplication of them: import Old hiding (MyType) import Old (MyType) instance ... MyType where <-- error!! Interesting that in Old module I'm exporting MyType without instances: module (... , MyType, ...) where Goal is to replace some instances and may be some types instead of copy-paste all module (something like patching or inheritance of module). === Best regards, Paul

Hello Paul, On Mon, Jan 08, 2018 at 03:20:20PM +0200, Pv wrote:
Hello, all.
Is it possible to import all types except some of instances and to re-defined hiding instances, so resulting (new) module will be the same types, mostly the same instances, but some of instances will be replaced?
Nope, instances are automatically imported! You can create newtypes and have them instances of what you need or check the newfangled `backpack` [1]! [1] https://ghc.haskell.org/trac/ghc/wiki/Backpack

Hello, Francesco. Actually the whole problem is that I have library (consisting of several modules: types, API calls, JSON instances, etc) to work with some REST service. Now I have 2 nodes with this service: version 1 and version 2, so API is little bit changed in version 2 (mostly in JSON instances, but types seems to be the same, API calls will be the same too). So, clients must work with both services: of version 1 and version 2. And I can create new library, but this will be big copy-paste, because mostly code (except JSON instances) will be the same. Different will be returned value in some API calls, maybe - I'm not sure. Nothing else. So, if I'll create new version of library: how they will live together with the same names, etc, only different version?! And common code-base will lead to complex bug-fixing and test modification. If I'll name new library like "oldlibv2" - problem with bug fixing and testing is still here. My idea was to "patch" in some way existing library by import some modules into new modules and reimplement some instances only. May be the same with API calls, I'm not sure here. I know that it's easy in F#, ML and Python, for example. Are backpacks something like ML modules? I see that they are not supported by stack. What does it mean? "import" will not work? Actually I don;t know - is some better way to solve such problem? I'm sure many of us communicate with some RESTfull APIs. Then APIs change. And your apps should work with old and new APIs (services), so you should clone existing library to support both versions (together, at the same time, in one client application!). === Best regards, Paul
Hello Paul,
On Mon, Jan 08, 2018 at 03:20:20PM +0200, Pv wrote:
Hello, all.
Is it possible to import all types except some of instances and to re-defined hiding instances, so resulting (new) module will be the same types, mostly the same instances, but some of instances will be replaced?
Nope, instances are automatically imported! You can create newtypes and have them instances of what you need or check the newfangled `backpack` [1]!
[1] https://ghc.haskell.org/trac/ghc/wiki/Backpack _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

The reason you don't get to override instances within a package is that
haskell accounts for the fact that a library user could import both old and
new, ending up with two conflicting instances for the same type.
If one of the types now needs two different JSON instances, one way to do
that is to wrap it in a newtype that has a different JSON instance.
data MyType = ... -- old type
newtype MyType_v2 = MyType_v2 MyType
-- data MyType_v2 = ... -- alternatively, define same structure, if it
didn't change.
instance JSON MyType_v2 = ... - slightly different json instance.
Then you can have a module that has a function that returns MyType_v2 from
its functions instead and exports a JSON instance for it. Users can import
either or both and will have access to both instances and both types.
You could also do it in the reverse, with a _v1 type, but old clients will
have to be updated.
As an addendum, you might future proof your API a little by having a
phantom type variable.
data V1
data V2
data MyType tag = ... -- old type
v1_func :: MyType V1
v1_func = undefined
v2_func :: MyType V2
v2_func = undefined
At the cost of a slightly more complicated API for your users. But that
won't protect you if MyType itself changes.
On Mon, Jan 8, 2018 at 9:31 AM, Baa
Hello, Francesco.
Actually the whole problem is that I have library (consisting of several modules: types, API calls, JSON instances, etc) to work with some REST service. Now I have 2 nodes with this service: version 1 and version 2, so API is little bit changed in version 2 (mostly in JSON instances, but types seems to be the same, API calls will be the same too).
So, clients must work with both services: of version 1 and version 2. And I can create new library, but this will be big copy-paste, because mostly code (except JSON instances) will be the same. Different will be returned value in some API calls, maybe - I'm not sure. Nothing else.
So, if I'll create new version of library: how they will live together with the same names, etc, only different version?! And common code-base will lead to complex bug-fixing and test modification. If I'll name new library like "oldlibv2" - problem with bug fixing and testing is still here.
My idea was to "patch" in some way existing library by import some modules into new modules and reimplement some instances only. May be the same with API calls, I'm not sure here.
I know that it's easy in F#, ML and Python, for example. Are backpacks something like ML modules? I see that they are not supported by stack. What does it mean? "import" will not work?
Actually I don;t know - is some better way to solve such problem? I'm sure many of us communicate with some RESTfull APIs. Then APIs change. And your apps should work with old and new APIs (services), so you should clone existing library to support both versions (together, at the same time, in one client application!).
=== Best regards, Paul
Hello Paul,
On Mon, Jan 08, 2018 at 03:20:20PM +0200, Pv wrote:
Hello, all.
Is it possible to import all types except some of instances and to re-defined hiding instances, so resulting (new) module will be the same types, mostly the same instances, but some of instances will be replaced?
Nope, instances are automatically imported! You can create newtypes and have them instances of what you need or check the newfangled `backpack` [1]!
[1] https://ghc.haskell.org/trac/ghc/wiki/Backpack _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

Thanks very much, David and Francesco! I got your solutions.
The reason you don't get to override instances within a package is that haskell accounts for the fact that a library user could import both old and new, ending up with two conflicting instances for the same type.
If one of the types now needs two different JSON instances, one way to do that is to wrap it in a newtype that has a different JSON instance.
data MyType = ... -- old type
newtype MyType_v2 = MyType_v2 MyType -- data MyType_v2 = ... -- alternatively, define same structure, if it didn't change.
instance JSON MyType_v2 = ... - slightly different json instance.
Then you can have a module that has a function that returns MyType_v2 from its functions instead and exports a JSON instance for it. Users can import either or both and will have access to both instances and both types.
You could also do it in the reverse, with a _v1 type, but old clients will have to be updated.
As an addendum, you might future proof your API a little by having a phantom type variable.
data V1 data V2 data MyType tag = ... -- old type
v1_func :: MyType V1 v1_func = undefined v2_func :: MyType V2 v2_func = undefined
At the cost of a slightly more complicated API for your users. But that won't protect you if MyType itself changes.
On Mon, Jan 8, 2018 at 9:31 AM, Baa
wrote: Hello, Francesco.
Actually the whole problem is that I have library (consisting of several modules: types, API calls, JSON instances, etc) to work with some REST service. Now I have 2 nodes with this service: version 1 and version 2, so API is little bit changed in version 2 (mostly in JSON instances, but types seems to be the same, API calls will be the same too).
So, clients must work with both services: of version 1 and version 2. And I can create new library, but this will be big copy-paste, because mostly code (except JSON instances) will be the same. Different will be returned value in some API calls, maybe - I'm not sure. Nothing else.
So, if I'll create new version of library: how they will live together with the same names, etc, only different version?! And common code-base will lead to complex bug-fixing and test modification. If I'll name new library like "oldlibv2" - problem with bug fixing and testing is still here.
My idea was to "patch" in some way existing library by import some modules into new modules and reimplement some instances only. May be the same with API calls, I'm not sure here.
I know that it's easy in F#, ML and Python, for example. Are backpacks something like ML modules? I see that they are not supported by stack. What does it mean? "import" will not work?
Actually I don;t know - is some better way to solve such problem? I'm sure many of us communicate with some RESTfull APIs. Then APIs change. And your apps should work with old and new APIs (services), so you should clone existing library to support both versions (together, at the same time, in one client application!).
=== Best regards, Paul
Hello Paul,
On Mon, Jan 08, 2018 at 03:20:20PM +0200, Pv wrote:
Hello, all.
Is it possible to import all types except some of instances and to re-defined hiding instances, so resulting (new) module will be the same types, mostly the same instances, but some of instances will be replaced?
Nope, instances are automatically imported! You can create newtypes and have them instances of what you need or check the newfangled `backpack` [1]!
[1] https://ghc.haskell.org/trac/ghc/wiki/Backpack _______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
_______________________________________________ Beginners mailing list Beginners@haskell.org http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

On Mon, Jan 08, 2018 at 04:31:53PM +0200, Baa wrote:
Actually I don;t know - is some better way to solve such problem? I'm sure many of us communicate with some RESTfull APIs. Then APIs change. And your apps should work with old and new APIs (services), so you should clone existing library to support both versions (together, at the same time, in one client application!).
A somewhat primitive but doable solution would be: instead of using instances pass a datatype around. E.g. data J a = J { readjs :: a -> MyTpe } myfun :: J a -> a -> Int -- when before it probably was -- myfun :: FromJson a => a -> Int You could enforce some sanity at type level with phantom types, e.g.: data InterfaceA data InterfaceB data J a b = -- something -- J is to be exported without (..) creaIntfA :: J a InterfaceA
Are backpacks something like ML modules?
Indeed backpack is a way to have an ML-like module system in Haskell. The question is interesting and a "real life" one. I urge you to post it on cafe- too, I am sure there will be some more ideas/solutions in there.
participants (4)
-
Baa
-
David McBride
-
Francesco Ariis
-
Pv