Replace instances of module

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

Replace instances of module

Baa
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
_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Replace instances of module

Francesco Ariis
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
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Replace instances of module

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
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Replace instances of module

David McBride
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 <[hidden email]> 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
> [hidden email]
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Replace instances of module

Francesco Ariis
In reply to this post by Baa
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.

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
Baa
Reply | Threaded
Open this post in threaded view
|

Re: Replace instances of module

Baa
In reply to this post by David McBride
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 <[hidden email]> 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
> > > [hidden email]
> > > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners 
> >
> > _______________________________________________
> > Beginners mailing list
> > [hidden email]
> > http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners
> >  

_______________________________________________
Beginners mailing list
[hidden email]
http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners