ADTs & Typeclasses

in Scala


Jan Schulte

Algebraic Data Types

In computer programming, more so functional programming and type theory, an algebraic data type is a kind of composite type, i.e., a type formed by combining other types.

Source Wikipedia

Algebraic Data Types

A type: Int, String, Double, …

ADTs are composite types

  • Sum types
  • Product types
  • Recursive types

Algebraic Data Types

Model data as combination of logical ***or*** and ***and***

  • Website Visitor ***is*** a logged in user ***or*** anonymous
  • A logged in user ***has*** an id ***and*** an email

Source Noel Welsh

# Sum Type

Sum type

Describes + types or logical or types

Thinking in ***is a*** relationships

Let's use some pseudo code first...

data TrafficLight = Green | Yellow | Red

Sum type

                data Day =
    Monday    | Tuesday  |
    Wednesday | Thursday |
    Friday    | Saturday |
    Sunday
                

Sum type

            data Computation =
    Success | Failure
            
            

Sum type

So how do we represent that in Scala?

# Product Type

Product type

Describes types or logical and types

Thinking in ***has a*** relationships

E.g. A Person ***has a*** name ***and*** an age

data Person = String & Int

Product type

A Point ***has *** an x ***and*** an y

                data Point = Double & Double
            

Product type

And now in Scala...

Product type

Product type 2.0

aka Records

Record type

A Person ***has a*** name ***and*** an age

Composition

A result of a computation ***is*** empty ***or*** it just ***has*** a return value

Composition

A result of a computation ***is*** either a String ***or*** an Int

Recursive types

A List ***is*** either an empty list ***or*** a construction of a head ***and*** a tail

Recursive types

A professor ***has*** a name ***and*** a class year ***and*** some students

Take aways

  • ADTs are simple
  • ADTs are powerful
  • Model your data as ADT!
  • Don't do stringly-typed programming!
  • Just use a f**king ADT - Mark Eibes

Typeclasses

Typeclasses

ADTs: Sum, Product, Recursive...

Awesome!

But how do we add functions to our ADTs?

Problem #1

Calculate the area of a shape

Problem #1 - OO approach

Expression problem

Expression problem

Adding subtypes is easy

Adding functions is difficult

GoF Visitor Pattern! Don't you dare!

Typeclasses to the rescue

Concept from FP languages (Haskell)

Separate functionality and data types

Are not OO classes! (thx Valentin)

Area Typeclass

Typeclasses - Simulacrum

Compiler plugin by Michael Pilquist

Reduce required typeclass boilerplate

Typeclasses - Simulacrum

                
import simulacrum._

@typeclass trait JsonSerialisable[A] {
  @op("toJson") def serialise(elem:A): String
}

implicit val intSerialisable = new JsonSerialisable[Int] {
  override def serialise(elem:Int) = "{\"elem\":"+ elem + "}"
}

import JsonSerialisable.ops._
1.toJson // prints {"elem":1}
                

More problems

Problem #2

Compare two days w.r.t. position in week

Problem #2

Let's do this in Java!

                
public enum Day {
    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
}
                

Problem #2

                
// class version 52.0 (52)
// access flags 0x4031
// signature Ljava/lang/Enum <LDay;>;
// declaration: Day extends java.lang.Enum <Day>
public final enum Day extends java/lang/Enum  {
                
            

Problem #2

int compareTo(E o)
Compares this enum with the specified object for order.
int ordinal()
Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).

Problem #2

class DaySpec extends Spec {
  "Sunday" should {
    "be greater than Monday" in {
      val result = Day.SUNDAY compareTo Day.MONDAY
      result must be_>(0)
    }
  }
  "Monday" should {
    "be smaller than Sunday" in {
      val result = Day.MONDAY compareTo Day.SUNDAY
      result must be_<(0)
    }
  }
}

Problem #2

[info] DaySpec
[info]
[info] Sunday should
[info]   + be greater than Monday
[info] Monday should
[info]   + be smaller than Sunday
            

Problem #2

Pretty cool, uh??

Well, NO!!

What about I18N? Americas, Middle East?

Order typeclass

Typelevel Cats library

                
/**
* The `Order` type class is used to define a total ordering on some type `A`.
*/
trait Order[A]{
  def compare(x: A, y: A): Int
}

Source Cats (excerpt)

Order typeclass

Show typeclass

Problem #3

Get a textual representation of an object

a.k.a toString

Problem #3

Problem #3

Problem #3

Problem #3

Do you know how toString() is used in your project?

  • Testing
  • Person(Name(Jan),Age(32))
  • Logging
  • Jan[age=32]
  • Json Serialisation

Problem #3

Do you know how toString() is used in your project?

  • Output Css classes (hmmkay)
  • Create Javascript tracking code (seriously?)
  • Create a checksum (dafuq???)

Show typeclass

                
/**
* A type class to provide textual representation
*/
trait Show[A] {
    def show(f: A): String
}

Source Cats

Show typeclass

Take aways

  • Typeclasses are amazing
  • TCs add functionality to your ADTs
  • TCs keep your ADT clean
  • Use simulacrum to avoid boilerplate
  • TC instances to support different types
  • TC instances to support different implementations

Thank you!

@janschultecom

github.com/janschultecom

Presentation Link: janschulte.com/2016-10-12-adts-typeclasses-scala