[GHC] #12708: RFC: Representation polymorphic Num
GHC
ghc-devs at haskell.org
Sun Jan 29 05:14:00 UTC 2017
#12708: RFC: Representation polymorphic Num
-------------------------------------+-------------------------------------
Reporter: Iceland_jack | Owner:
Type: feature request | Status: new
Priority: normal | Milestone:
Component: Core Libraries | Version: 8.0.1
Resolution: | Keywords:
| LevityPolymorphism
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: #12980 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by goldfire):
An exhaustive search through `ghc-prim` and `base` found 34 (!) classes
that can be generalized this way:
{{{
Eq, Ord, Functor, Applicative, Monad, MonadFail, MonadFix, MonadIO,
Bifoldable, Bifunctor, HasResolution, Foldable, Eq1, Ord1, Eq2, Ord2,
IsString, TestCoercion, TestEquality, Storable, IsList, Num, Real,
Fractional, Generic, Generic1, GHCiSandboxIO, BufferedIO, RawIO,
IsLabel, PrintfType, HPrintfType, PrintfArg, IsChar
}}}
Some are surely more useful to generalize than others. But wow!
More classes morally could be included in this list but for two limiting
factors:
- Many classes use lists somewhere. (For example, `Show`.) However, we
could define a family of list types, one for each representation (which
would box unboxed tuples), and then use a type family to select the
appropriate list type, allowing generalizations of classes that use lists.
- Several classes (e.g., `Integral`) use tuples, preventing
generalization. But we could just use unboxed tuples and away we go.
Another annoyance was that `Applicative` can be generalized to make its
parameter `f :: Type -> TYPE r`, but not `f :: TYPE r1 -> TYPE r2`. The
latter is impossible because the class definition mentions `f (a -> b)`,
and functions are always lifted.
It would be lovely, though, to ponder the possibility of `class
Applicative (f :: forall (r1 :: RuntimeRep). TYPE r1 -> TYPE r2)`, where
`Applicative` would then have a higher-rank kind. And, we could generalize
`IO` (it's implemented using an unboxed tuple, after all) and then `IO`
could be made an instance of this new `Applicative`. `Monad` would soon
follow, and you'd then be able to return unboxed values in `do`-notation.
A final note: In testing all this, I had to add `default` signatures
imposing a `r ~ LiftedRep` constraint whenever a generalized class had a
default implementation, because the default implementation would work only
at kind `Type`. This works, but it's disappointing that there can be no
defaults at representations other than `LiftedRep`. However, I've realized
we ''can''. Instead of `r ~ LiftedRep` in the `default` signature, impose
a `Typeable r` constraint. Then we can do a runtime type test to figure
out the representation and to squash the levity polymorphism. (This
actually works.) A sufficiently smart compiler would be able to optimize
away the runtime type test in any non-levity-polymorphic class instance.
And we're just left with happiness and a wicked powerful type system.
My (rushed, somewhat shoddy) work on this is
[https://github.com/goldfirere/ghc/tree/lev-poly-base here]. I don't
expect that to ever be merged -- I just was exploring the possibility.
--
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/12708#comment:29>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler
More information about the ghc-tickets
mailing list