Created
August 14, 2019 07:13
-
-
Save sideeffffect/bbfeda29057ad707bf8382e9b999572d to your computer and use it in GitHub Desktop.
Scala Type Classes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.avast.scalamodulesexperiment | |
object Polymorphism { | |
trait Animal { | |
def makeSound: String | |
} | |
class Dog extends Animal { | |
override def makeSound: String = "haf" | |
} | |
class Cat extends Animal { | |
override def makeSound: String = "mnau" | |
} | |
def play(animal: Animal): String = { | |
"my animal make sound " + animal.makeSound | |
} | |
sealed trait List[A] | |
case class Empty[A]() extends List[A] | |
case class Cons[A](head: A, tail: List[A]) extends List[A] | |
def length[A](list: List[A]): Int = | |
list match { | |
case Empty() => 0 | |
case Cons(_, tail) => 1 + length(tail) | |
} | |
def second[A, B](a: A, b: B): B = b | |
val person = new { | |
val fn = "John" | |
val ln = "Smith" | |
val num = 123 | |
} | |
def hello(p: { | |
val fn: String | |
val num: String | |
}): String = { | |
"hello " + p.fn + " " + p.num + "!" | |
} | |
def plus(a: Int, b: Int): String = | |
(a + b).toString | |
def plus(a: Double, b: Double): Double = | |
a + b | |
def plus(a: String, b: String): String = | |
"hello " + a + " " + b | |
} | |
object tcExplicit { | |
sealed trait List[A] | |
case class Empty[A]() extends List[A] | |
case class Cons[A](head: A, tail: List[A]) extends List[A] | |
case class Person(name: String, age: Int) | |
trait Eq[A] { | |
def equal(x: A, y: A): Boolean | |
} | |
object EqPerson extends Eq[Person] { | |
override def equal(x: Person, y: Person): Boolean = | |
??? | |
} | |
def ifSame[A, B, C](x: A, y: A, b: B, c: C)(EqA: Eq[A]): Either[B, C] = | |
if (EqA.equal(x, y)) { | |
Left(b) | |
} else { | |
Right(c) | |
} | |
val p1: Person = ??? | |
val p2: Person = ??? | |
ifSame(p1, p2, 42, "asdf")(EqPerson) | |
def EqList[A](EqA: Eq[A]): Eq[List[A]] = new Eq[List[A]] { | |
override def equal(x: List[A], y: List[A]): Boolean = { | |
(x, y) match { | |
case (Empty(), Empty()) => true | |
case (Cons(h1, t1), Cons(h2, t2)) => | |
if (EqA.equal(h1, h2)) | |
equal(t1, t2) | |
else | |
false | |
case _ => false | |
} | |
} | |
} | |
val p3: Person = ??? | |
ifSame(Cons(p1, Empty()), Cons(p2, Empty()), 42, "asdf")(EqList(EqPerson)) | |
trait Comparator[A] extends Eq[A] { | |
def compare(x: A, y: A): Int | |
override def equal(x: A, y: A): Boolean = compare(x, y) == 1 | |
} | |
object ComparatorPerson extends Comparator[Person] { | |
override def compare(x: Person, y: Person): Int = | |
x.name.compare(y.name) match { | |
case 0 => x.age.compare(y.age) | |
case i => i | |
} | |
} | |
ifSame(p1, p2, 42, "asdf")(ComparatorPerson) | |
trait Semigroup[A] { | |
def combine(x: A, y: A): A | |
} | |
trait Monoid[A] extends Semigroup[A] { | |
def empty: A | |
} | |
def accumulate[A](list: List[A])(Monoid: Monoid[A]): A = | |
list match { | |
case Empty() => Monoid.empty | |
case Cons(head, tail) => | |
val accTail = accumulate(tail)(Monoid) | |
Monoid.combine(head, accTail) | |
} | |
} | |
object implicitMachinery { | |
case class Person(name: String, age: Int) | |
sealed trait List[A] | |
case class Empty[A]() extends List[A] | |
case class Cons[A](head: A, tail: List[A]) extends List[A] | |
trait Eq[A] { | |
def equal(x: A, y: A): Boolean | |
} | |
implicit object EqPerson extends Eq[Person] { | |
override def equal(x: Person, y: Person): Boolean = ??? | |
} | |
implicit def EqList[A](implicit EqA: Eq[A]): Eq[List[A]] = new Eq[List[A]] { | |
override def equal(x: List[A], y: List[A]): Boolean = { | |
(x, y) match { | |
case (Empty(), Empty()) => true | |
case (Cons(h1, t1), Cons(h2, t2)) => | |
if (EqA.equal(h1, h2)) | |
equal(t1, t2) | |
else | |
false | |
case _ => false | |
} | |
} | |
} | |
def ifSame[A, B, C](x: A, y: A, b: B, c: C)( | |
implicit EqA: Eq[A]): Either[B, C] = | |
if (EqA.equal(x, y)) { | |
Left(b) | |
} else { | |
Right(c) | |
} | |
val p1: Person = ??? | |
val p2: Person = ??? | |
ifSame(Cons(p1, Empty()): List[Person], Cons(p2, Empty()), 42, "asdf") | |
} | |
object interfaces { | |
trait Equatable[A] { | |
def equal(other: A): Boolean | |
} | |
case class Human(name: String, age: Int) extends Equatable[Human] { | |
override def equal(other: Human): Boolean = ??? | |
} | |
def ifSame2[A <: Equatable[A], B, C](x: A, y: A, b: B, c: C): Either[B, C] = | |
if (x.equal(y)) { | |
Left(b) | |
} else { | |
Right(c) | |
} | |
class List2[A <: Equatable[A]] extends Equatable[List2[A]] { | |
override def equal(other: List2[A]): Boolean = ??? | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment