Difference between revisions of "Orphan instance"
(making the presentation a bit more balanced with more related reading) |
|||
(10 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
⚫ | |||
− | == Question == |
||
⚫ | Type class instances are special in that they don't have a name and cannot be imported explicitly. This also means that they cannot be ''excluded'' explicitly. All instances defined in a module A are imported automatically when importing A, or importing any module that imports A, directly or indirectly. |
||
− | What is an Orphan instance and why is it bad? |
||
⚫ | Say you want to define an alternative instance to an existing instance. This is a bad thing, since if two instances for the same class/type pair are in scope, then you cannot describe in Haskell 98 which instance to use. If you want to use multiple instances for the same class/type, you have to ensure that they are never imported together in a module somewhen. It is almost impossible to assert that, or put differently, it would reduce the composability of libraries considerably. |
||
− | == Answer == |
||
+ | The <hask>Monad</hask> instance of <hask>Either</hask> is a good example. |
||
⚫ | |||
+ | It is not defined where <hask>Either</hask> is defined, thus all of its <hask>Monad</hask> instances must be orphan. |
||
+ | Instead it is defined both in <hask>Control.Monad.Error</hask> of the [[Monad Transformer Library]] |
||
+ | and in <hask>Control.Monad.Trans.Error</hask> of its lightweight cousin the 'transformers' package. |
||
+ | Since some packages use MTL and others 'transformers' it becomes difficult to use that instance at all, |
||
+ | although both instances are equivalent! |
||
+ | Practical advice: |
||
+ | The [[Exception|explicit-exception]] package with its <hask>Exceptional</hask> might be a better choice to use since it avoids the current problem with orphan Monad instances of <hask>Either</hask>. |
||
⚫ | Actually, non-orphan instances can avoid definition of [[multiple instances]]. For defining an instance you have to import the class and the type and then you will automatically have the according non-orphan instances imported, too. If you want to define a new instance then the compiler will reject it immediately. |
||
⚫ | |||
− | Say you want to make use of a type class instance in your module, then you must import both the class and the type directly, or you must import modules which itself import at some point the class and at some other point the type. If there is a non-orphan instance, you automatically get the instance imported. This way the compiler can restrict the set of modules to look for an instance if you want to apply it. So the problem is partially an efficiency problem, but this is not all. |
||
+ | ==When Orphan Instances can be useful== |
||
⚫ | Say you want to define an alternative instance to an existing instance. This is a bad thing, since if two instances for the same class/type pair are in scope, then you cannot describe in Haskell 98 which instance to use. If you want to use multiple instances for the same class/type, you have to ensure |
||
+ | It is worth noting that Orphan Instances can be viewed as a mechanism for writing modules of code with a fixed typed interface, but parameterized over the choice of implementation. In this case, Orphan Instances act as a sort of plugin architecture for providing alternative implementations with a uniform interface. |
||
− | |||
⚫ | Actually, non-orphan instances can avoid definition of multiple instances. For defining an instance you have to import the class and the type and then you will automatically have the according non-orphan instances imported, too. If you want to define a new instance then the compiler will reject it immediately. |
||
+ | A basic treatment of the relationship between type classes and modules (in the SML sense of modules) can be found at http://www.mpi-sws.org/~dreyer/papers/mtc/main-short.pdf and http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf |
||
== See also == |
== See also == |
||
Line 20: | Line 26: | ||
* [[Multiple instances]] |
* [[Multiple instances]] |
||
* Libraries mailing list on [http://www.haskell.org/pipermail/libraries/2008-August/010399.html Orphan instances can be good] |
* Libraries mailing list on [http://www.haskell.org/pipermail/libraries/2008-August/010399.html Orphan instances can be good] |
||
+ | * [http://www.haskell.org/pipermail/haskell-cafe/2011-July/094014.html Ideas] on possible compiler warnings for coping with orphan instances |
||
+ | * Libraries mailing list on [http://www.haskell.org/pipermail/libraries/2012-September/018398.html Relaxin the PVP with regards to adding instances] |
||
* [http://modula3.elegosoft.com/pm3/pkg/modula3/src/discussion/partialRev.html Partial Revelation feature] of Modula-3 which causes similar problems like Haskell's type class instances |
* [http://modula3.elegosoft.com/pm3/pkg/modula3/src/discussion/partialRev.html Partial Revelation feature] of Modula-3 which causes similar problems like Haskell's type class instances |
||
Revision as of 06:39, 23 June 2013
An orphan instance is a type class instance for class C and type T which is neither defined in the module where C is defined nor in the module where T is defined.
Type class instances are special in that they don't have a name and cannot be imported explicitly. This also means that they cannot be excluded explicitly. All instances defined in a module A are imported automatically when importing A, or importing any module that imports A, directly or indirectly.
Say you want to define an alternative instance to an existing instance. This is a bad thing, since if two instances for the same class/type pair are in scope, then you cannot describe in Haskell 98 which instance to use. If you want to use multiple instances for the same class/type, you have to ensure that they are never imported together in a module somewhen. It is almost impossible to assert that, or put differently, it would reduce the composability of libraries considerably.
The Monad
instance of Either
is a good example.
It is not defined where Either
is defined, thus all of its Monad
instances must be orphan.
Instead it is defined both in Control.Monad.Error
of the Monad Transformer Library
and in Control.Monad.Trans.Error
of its lightweight cousin the 'transformers' package.
Since some packages use MTL and others 'transformers' it becomes difficult to use that instance at all,
although both instances are equivalent!
Practical advice:
The explicit-exception package with its Exceptional
might be a better choice to use since it avoids the current problem with orphan Monad instances of Either
.
Actually, non-orphan instances can avoid definition of multiple instances. For defining an instance you have to import the class and the type and then you will automatically have the according non-orphan instances imported, too. If you want to define a new instance then the compiler will reject it immediately.
When Orphan Instances can be useful
It is worth noting that Orphan Instances can be viewed as a mechanism for writing modules of code with a fixed typed interface, but parameterized over the choice of implementation. In this case, Orphan Instances act as a sort of plugin architecture for providing alternative implementations with a uniform interface.
A basic treatment of the relationship between type classes and modules (in the SML sense of modules) can be found at http://www.mpi-sws.org/~dreyer/papers/mtc/main-short.pdf and http://www.cse.unsw.edu.au/~chak/papers/modules-classes.pdf
See also
- Multiple instances
- Libraries mailing list on Orphan instances can be good
- Ideas on possible compiler warnings for coping with orphan instances
- Libraries mailing list on Relaxin the PVP with regards to adding instances
- Partial Revelation feature of Modula-3 which causes similar problems like Haskell's type class instances