Type classes
Dmytro Mitin
https://stepik.org/course/Introduction-to-programming-
with-dependent-types-in-Scala-2294/
March 2017
Dmytro Mitin Type classes
Inheritance in Java (implementing interface)
public interface Comparable<A> {
boolean cmp(A a1, A a2);
}
public class MyClass implements Comparable<MyClass> {
private int x;
@Override
public boolean cmp(MyClass a1, MyClass a2) {
return a1.x < a2.x;
}
}
public class OtherClass implements Comparable<OtherClass> {
private List<Integer> xs;
@Override
public boolean cmp(OtherClass a1, OtherClass a2) {
return a1.xs.get(0) < a2.xs.get(0);
}
}
Dmytro Mitin Type classes
Inheritance in Scala (extending trait)
trait Comparable[A] {
def cmp(a1: A, a2: A): Boolean
}
class MyClass(val x: Int) extends Comparable[MyClass] {
override def cmp(a1: MyClass, a2: MyClass): Boolean =
a1.x < a2.x
}
class OtherClass(val xs: List[Int]) extends Comparable[OtherClass] {
override def cmp(a1: OtherClass, a2: OtherClass): Boolean =
a1.xs.head < a2.xs.head
}
Dmytro Mitin Type classes
Type classes in Haskell
class Comparable a where
cmp :: a -> a -> Bool
instance Comparable Int where
cmp x y = x < y
instance Comparable a => Comparable [a] where
cmp xs ys = cmp (head xs) (head ys)
cmp (1 :: Int) 2
cmp [1 :: Int, 2] [2, 0]
> True
Dmytro Mitin Type classes
Implicits in Scala
Implicit parameters
def f(x: Int)(implicit y: String): String = x.toString + y
implicit val s: String = "abc"
f(10)
> 10abc
Implicit objects
class MyClass
def f(x: Int)(implicit y: MyClass): Int = x + y.hashCode
// implicit val obj = new MyClass
implicit object obj extends MyClass
f(10)
> ... /* some number */
Dmytro Mitin Type classes
Implicits in Scala
Implicit conversions
implicit def f(x: Int): String = x.toString + "abc"
def g(s: String): List[Char] = s.toList
g(123)
> List(1, 2, 3, a, b, c)
Implicit classes
implicit class MyClass(x: Int) {
def myMethod: Int = x + 1
}
123.myMethod
> 124
Dmytro Mitin Type classes
Type classes in Scala
trait Comparable[A] {
def cmp(a1: A, a2: A): Boolean
}
implicit object intComparable extends Comparable[Int] {
override def cmp(a1: Int, a2: Int): Boolean = a1 < a2
}
implicit class ComparableInt(x: Int) {
def cmp(y: Int): Boolean =
implicitly[Comparable[Int]].cmp(x, y)
}
Dmytro Mitin Type classes
Type classes in Scala
implicit def listComparable[A: Comparable]: Comparable[List[A]] =
new Comparable[List[A]] {
override def cmp(a1: List[A], a2: List[A]): Boolean =
implicitly[Comparable[A]].cmp(a1.head, a2.head)
}
// implicit def listComparable[A](implicit elementComparable:
// Comparable[A]): Comparable[List[A]] =
// new Comparable[List[A]] {
// override def cmp(a1: List[A], a2: List[A]): Boolean =
// elementComparable.cmp(a1.head, a2.head)
// }
// implicit def listComparable[A: Comparable]: Comparable[List[A]] =
// (a1: List[A], a2: List[A]) =>
// implicitly[Comparable[A]].cmp(a1.head, a2.head)
Dmytro Mitin Type classes
Type classes in Scala
implicit class ComparableList[A: Comparable](list: List[A]) {
def cmp(other: List[A]): Boolean =
implicitly[Comparable[List[A]]].cmp(list, other)
}
implicitly[Comparable[Int]].cmp(1, 2)
1.cmp(2)
1 cmp 2
implicitly[Comparable[List[Int]]].cmp(List(1, 2), List(2, 0))
List(1, 2).cmp(List(2, 0))
> true
Dmytro Mitin Type classes
Simulacrum library
build.sbt
libraryDependencies += "com.github.mpilquist" %%
"simulacrum" % "0.10.0"
addCompilerPlugin("org.scalameta" % "paradise" %
"3.0.0-beta4" cross CrossVersion.full)
import simulacrum.
@typeclass trait Comparable[A] {
@op("<<<") def cmp(a1: A, a2: A): Boolean
}
implicit object intComparable extends Comparable[Int] {
override def cmp(a1: Int, a2: Int): Boolean = a1 < a2
}
Dmytro Mitin Type classes
Simulacrum library
implicit def listComparable[A: Comparable]: Comparable[List[A]] =
new Comparable[List[A]] {
override def cmp(a1: List[A], a2: List[A]): Boolean =
implicitly[Comparable[A]].cmp(a1.head, a2.head)
}
import Comparable.ops.
1 <<< 2
List(1, 2) <<< List(2, 0)
> true
Dmytro Mitin Type classes

Type classes

  • 1.
  • 2.
    Inheritance in Java(implementing interface) public interface Comparable<A> { boolean cmp(A a1, A a2); } public class MyClass implements Comparable<MyClass> { private int x; @Override public boolean cmp(MyClass a1, MyClass a2) { return a1.x < a2.x; } } public class OtherClass implements Comparable<OtherClass> { private List<Integer> xs; @Override public boolean cmp(OtherClass a1, OtherClass a2) { return a1.xs.get(0) < a2.xs.get(0); } } Dmytro Mitin Type classes
  • 3.
    Inheritance in Scala(extending trait) trait Comparable[A] { def cmp(a1: A, a2: A): Boolean } class MyClass(val x: Int) extends Comparable[MyClass] { override def cmp(a1: MyClass, a2: MyClass): Boolean = a1.x < a2.x } class OtherClass(val xs: List[Int]) extends Comparable[OtherClass] { override def cmp(a1: OtherClass, a2: OtherClass): Boolean = a1.xs.head < a2.xs.head } Dmytro Mitin Type classes
  • 4.
    Type classes inHaskell class Comparable a where cmp :: a -> a -> Bool instance Comparable Int where cmp x y = x < y instance Comparable a => Comparable [a] where cmp xs ys = cmp (head xs) (head ys) cmp (1 :: Int) 2 cmp [1 :: Int, 2] [2, 0] > True Dmytro Mitin Type classes
  • 5.
    Implicits in Scala Implicitparameters def f(x: Int)(implicit y: String): String = x.toString + y implicit val s: String = "abc" f(10) > 10abc Implicit objects class MyClass def f(x: Int)(implicit y: MyClass): Int = x + y.hashCode // implicit val obj = new MyClass implicit object obj extends MyClass f(10) > ... /* some number */ Dmytro Mitin Type classes
  • 6.
    Implicits in Scala Implicitconversions implicit def f(x: Int): String = x.toString + "abc" def g(s: String): List[Char] = s.toList g(123) > List(1, 2, 3, a, b, c) Implicit classes implicit class MyClass(x: Int) { def myMethod: Int = x + 1 } 123.myMethod > 124 Dmytro Mitin Type classes
  • 7.
    Type classes inScala trait Comparable[A] { def cmp(a1: A, a2: A): Boolean } implicit object intComparable extends Comparable[Int] { override def cmp(a1: Int, a2: Int): Boolean = a1 < a2 } implicit class ComparableInt(x: Int) { def cmp(y: Int): Boolean = implicitly[Comparable[Int]].cmp(x, y) } Dmytro Mitin Type classes
  • 8.
    Type classes inScala implicit def listComparable[A: Comparable]: Comparable[List[A]] = new Comparable[List[A]] { override def cmp(a1: List[A], a2: List[A]): Boolean = implicitly[Comparable[A]].cmp(a1.head, a2.head) } // implicit def listComparable[A](implicit elementComparable: // Comparable[A]): Comparable[List[A]] = // new Comparable[List[A]] { // override def cmp(a1: List[A], a2: List[A]): Boolean = // elementComparable.cmp(a1.head, a2.head) // } // implicit def listComparable[A: Comparable]: Comparable[List[A]] = // (a1: List[A], a2: List[A]) => // implicitly[Comparable[A]].cmp(a1.head, a2.head) Dmytro Mitin Type classes
  • 9.
    Type classes inScala implicit class ComparableList[A: Comparable](list: List[A]) { def cmp(other: List[A]): Boolean = implicitly[Comparable[List[A]]].cmp(list, other) } implicitly[Comparable[Int]].cmp(1, 2) 1.cmp(2) 1 cmp 2 implicitly[Comparable[List[Int]]].cmp(List(1, 2), List(2, 0)) List(1, 2).cmp(List(2, 0)) > true Dmytro Mitin Type classes
  • 10.
    Simulacrum library build.sbt libraryDependencies +="com.github.mpilquist" %% "simulacrum" % "0.10.0" addCompilerPlugin("org.scalameta" % "paradise" % "3.0.0-beta4" cross CrossVersion.full) import simulacrum. @typeclass trait Comparable[A] { @op("<<<") def cmp(a1: A, a2: A): Boolean } implicit object intComparable extends Comparable[Int] { override def cmp(a1: Int, a2: Int): Boolean = a1 < a2 } Dmytro Mitin Type classes
  • 11.
    Simulacrum library implicit deflistComparable[A: Comparable]: Comparable[List[A]] = new Comparable[List[A]] { override def cmp(a1: List[A], a2: List[A]): Boolean = implicitly[Comparable[A]].cmp(a1.head, a2.head) } import Comparable.ops. 1 <<< 2 List(1, 2) <<< List(2, 0) > true Dmytro Mitin Type classes