kittens is a Scala library which provides instances of type classes from the Cats library for arbitrary algebraic data types using shapeless-based automatic type class derivation. It also provides some utility functions related to cats.Applicative such as lift, traverse and sequence to HList, Record and arbitrary parameter list.
kittens is part of the Typelevel family of projects. It is an Open Source project under the Apache License v2, hosted on github. Binary artefacts will be published to the Sonatype OSS Repository Hosting service and synced to Maven Central.
It is available for Scala 2.11 and 2.12, and Scala.js.
To get started with SBT, simply add the following to your build.sbt file:
libraryDependencies += "org.typelevel" %% "kittens" % "1.0.0-RC1"
scala> import cats.implicits._, cats._
scala> case class Cat[Food](food: Food, foods: List[Food])
defined class Cat
scala> val cat = Cat(1, List(2, 3))
cat: Cat[Int] = Cat(1,List(2, 3))
scala> implicit val fc = cats.derive.functor[Cat]
FC: cats.Functor[Cat] = cats.derived.MkFunctor2$$anon$4@1c60573f
scala> cat.map(_ + 1)
res0: Cat[Int] = Cat(2,List(3, 4))
scala> case class Address(street: String, city: String, state: String)
scala> case class ContactInfo(phoneNumber: String, address: Address)
scala> case class People(name: String, contactInfo: ContactInfo)
scala> val mike = People("Mike", ContactInfo("202-295-3928", Address("1 Main ST", "Chicago", "IL")))
scala> import cats._,cats.implicits._
scala> //existing Show instance for Address
scala> implicit val addressShow: Show[Address] = new Show[Address] {
def show(a: Address) = s"${a.street}, ${a.city}, ${a.state}"
}
scala> implicit val peopleShow = derive.show[People] //auto derive Show for People
scala> mike.show
res0: String = People(name = Mike, contactInfo = ContactInfo(phoneNumber = 202-295-3928, address = 1 Main ST, Chicago, IL))
Note that in this example, the derivation auto derived all referenced class but still respect the existing instance in scope.
Note that to run these examples you need on partial unification to overcome SI-2712. An easy way to achieve that is to use this sbt-plugin, add to your project/plugs.sbt
:
addSbtPlugin("org.lyranthe.sbt" % "partial-unification" % "1.1.0")
scala> import cats.implicits._, cats.sequence._
import cats.implicits._
import cats.sequence._
scala> val f1 = (_: String).length
f1: String => Int = <function1>
scala> val f2 = (_: String).reverse
f2: String => String = <function1>
scala> val f3 = (_: String).toFloat
f3: String => Double = <function1>
scala> val f = sequence(f1, f2, f3)
f: String => shapeless.::[Int,shapeless.::[String,shapeless.::[Float,shapeless.HNil]]] = <function1>
scala> f("42.0")
res0: shapeless.::[Int,shapeless.::[String,shapeless.::[Float,shapeless.HNil]]] = 4 :: 0.24 :: 42.0 :: HNil
//or generic over ADTs
scala> case class MyCase(a: Int, b: String, c: Float)
defined class MyCase
scala> val myGen = sequenceGeneric[MyCase]
myGen: cats.sequence.sequenceGen[MyCase] = cats.sequence.SequenceOps$sequenceGen@63ae3243
scala> val f = myGen(a = f1, b = f2, c = f3)
f: String => MyCase = <function1>
scala> f("42.0")
res1: MyCase = MyCase(4,0.24,42.0)
Traverse works similarly but you need a Poly.
scala> import cats._, implicits._, lift._
import cats._
import implicits._
import lift._
scala> def foo(x: Int, y: String, z: Float) = s"$x - $y - $z"
scala> val lifted = Applicative[Option].liftA(foo _)
lifted: (Option[Int], Option[String], Option[Float]) => Option[String] = <function3>
scala> lifted(Some(1), Some("a"), Some(3.2f))
res0: Option[String] = Some(1 - a - 3.2)
Typelevel Scala provides a partial fix for SI-7046 which can present obstacles to the uses of
shapeless's Generic
and LabelledGeneric
for the sealed trait at the root of an ADT such as you find in Kittens. If
it appears that these two type classes are unable to find (all of) the subclasses of an ADT root trait then please try
using Typelevel Scala and see if it resolves the issue.
To use Typelevel Scala you should,
-
Update your
project/build.properties
to require SBT 0.13.13 or later,sbt.version=0.13.13
-
Add the following to your
build.sbt
immediately next to where you setscalaVersion
,scalaOrganization := "org.typelevel"
If this does resolve the problem, please lend your support to the pull request being merged in Lightbend Scala.
The Kittens project supports the Typelevel code of conduct and wants all of its channels (mailing list, Gitter, github, etc.) to be welcoming environments for everyone.
kittens is built with SBT 0.13.9 or later, and its master branch is built with Scala 2.11.7 by default.
- Cody Allen [email protected] @fourierstrick
- Kailuo Wang [email protected] @kailuowang
- Miles Sabin [email protected] @milessabin
- Georgi Krastev [email protected] @Joro_Kr
- Fabio Labella [email protected] @SystemFw
- Your name here :-)