Safe Haskell | None |
---|---|
Language | Haskell2010 |
Documentation
class (~R#) k k a b => Coercible k a b #
Coercible
is a two-parameter class that has instances for types a
and b
if
the compiler can infer that they have the same representation. This class
does not have regular instances; instead they are created on-the-fly during
type-checking. Trying to manually declare an instance of Coercible
is an error.
Nevertheless one can pretend that the following three kinds of instances exist. First, as a trivial base-case:
instance a a
Furthermore, for every type constructor there is
an instance that allows to coerce under the type constructor. For
example, let D
be a prototypical type constructor (data
or
newtype
) with three type arguments, which have roles nominal
,
representational
resp. phantom
. Then there is an instance of
the form
instance Coercible b b' => Coercible (D a b c) (D a b' c')
Note that the nominal
type arguments are equal, the
representational
type arguments can differ, but need to have a
Coercible
instance themself, and the phantom
type arguments can be
changed arbitrarily.
The third kind of instance exists for every newtype NT = MkNT T
and
comes in two variants, namely
instance Coercible a T => Coercible a NT
instance Coercible T b => Coercible NT b
This instance is only usable if the constructor MkNT
is in scope.
If, as a library author of a type constructor like Set a
, you
want to prevent a user of your module to write
coerce :: Set T -> Set NT
,
you need to set the role of Set
's type parameter to nominal
,
by writing
type role Set nominal
For more details about this feature, please refer to Safe Coercions by Joachim Breitner, Richard A. Eisenberg, Simon Peyton Jones and Stephanie Weirich.
Since: 4.7.0.0
coerce :: Coercible * a b => a -> b #
The function coerce
allows you to safely convert between values of
types that have the same representation with no run-time overhead. In the
simplest case you can use it instead of a newtype constructor, to go from
the newtype's concrete type to the abstract type. But it also works in
more complicated settings, e.g. converting a list of newtypes to a list of
concrete types.
(#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c infixr 9 Source #
It may be better to use (
instead of
#.
)(
to avoid potential efficiency
problems relating to #7542. The problem, in a nutshell:.
)
If N
is a newtype constructor, then N x
will always have the same
representation as x
(something similar applies for a newtype
deconstructor). However, if f
is a function,
N .
f = x -> N (f x)
This looks almost the same as f
, but the eta expansion lifts it--the
lhs could be _|_
, but the rhs never is. This can lead to very
inefficient code. Thus we steal a technique from Shachaf and Edward
Kmett and adapt it to the current (rather clean) setting. Instead of
using N
, we use .
fN
, which
is just.#
f
coerce
f `asTypeOf'
(N.
f)
That is, we just *pretend* that f
has the right type, and thanks to
the safety of coerce
, the type checker guarantees that nothing really
goes wrong. We still have to be a bit careful, though: remember that
#.
completely ignores the *value* of its left operand.