Dear lists,
this mail summarises some plans from NE Scala to bring shapeless and
other libraries (scalaz, …) closer together.
*The problem*
You want to derive type class instances for case classes. Imagine you
have a couple of types like:
case class Foo(i: Int, s: String)
and now you want a Monoid for that. Easy enough to define, but you don't
want all that boilerplate.
*Current state of the affairs*
If you were using shapeless, you'd define some isomorphisms, and it'd
derive your stuff automatically, as demonstrated in [1]. However, this
example defines
1) its own Monoid class
2) an implicit to derive a Monoid for HNil
3) an implicit to derive a Monoid for HCons
4) an implicit to derive a Monoid using an Iso
Luckily, there are already two libraries defining Monoids [2,3]. Now, we
just have to find out how to abstract over steps 2 to 4.
Now, Scalaz to the rescue [4]: It contains a type class abstracting over
precisely those things. It has a couple of drawbacks, though:
- it uses Scalaz HLists, which lack all those heavy machinery like
deriving isomorphisms between case classes and HLists
- for some reason, deriving the instances automatically doesn't work
(compiler crashes)
Not a very great rescue, unfortunately.
*How can this be fixed?*
Put this abstraction – a type class called "TypeClass", since it's a
type class abstracting over type classes – into shapeless. I created a
branch in my fork of shapeless, based on the release of 1.2.3 for Scala
2.10 [5,6].
Users who want to derive a Monoid for their case classes now have to do
the following:
1) Define a `TypeClass` instance.
2) Publish an `Iso`.
3) ???
4) PROFIT!
Luckily, we can get rid of step 1 by putting this sort of stuff into a
3rd-party-library, called "shapeless-contrib". It would contain all
sorts of instances for Scalaz and Spire, readily to use for your
convenience.
*What needs to be done?*
I already talked with Miles about the creation of some sort of stable
branch (maybe 1.2.x or even 1.3.x), renaming the macro-paradise efforts
to 2.x [7]. Then, I'll put together a small pull request for my changes
against that branch. Once all that is done, I'll create a new project
which depends on shapeless, scalaz, spire, …
In the end, using your case classes as monoids will require a couple of
library dependencies in your build and some imports in your code. Does
that sound good?
Regards
Lars
[1]
<
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/monoids.scala>
[2] <
https://github.com/scalaz/scalaz/tree/scalaz-seven>
[3] <
https://github.com/non/spire>
[4]
<
https://github.com/scalaz/scalaz/blob/scalaz-seven/typelevel/src/main/scala/scalaz/typelevel/TypeClass.scala>
[5] <
https://github.com/larsrh/shapeless/compare/scala-2.10...a500e3f>
[6] Side note: I think for this matter, "2.10 only" is a good choice
since it's stable. It might be possible to support 2.9 too, since my
approach doesn't use any macros (yet :-)).
[7] Since I don't follow the development of shapeless closely, I have no
idea how the branches are organised right now. Miles, can you comment on
that? Maybe 'master' would be the most appropriate branch.