Motivation and Mechanics behind some aspects of Shapeless

Preview:

Citation preview

Motivation and Mechanics behind some aspects of

Shapeless

Plan

•Motivation•HList•Coproduct•Generic•Example

Motivation

Theory: product, coproduct and type classes

• Product: a and b.

• Coproduct: a or b.

• Type class: operations possible on a type.

type Phone = (Manufacturer, Model, Imei)

sealed trait Device

trait Phone extends Device

trait Laptop extends Device

trait ShowCsv[A] {

def showCsv(a: A): String

}

Why Shapeless?

•Manipulation of the Scala data types (e.g. treat a case class as a list).

•Type-level representations of data structures and operations over them.

HList: Generalisation of the product type

HList: Implementation

sealed trait HList

case class ::[+H, +T <: HList](head : H, tail : T) extends HList

case object HNil extends HList

HList: Example – Head of an Empty Listscala> List(1).head

res0: Int = 1

scala> Nil.head

java.util.NoSuchElementException: head of empty list

at scala.collection.immutable.Nil$.head(List.scala:420)

... 42 elided

scala> (1 :: HNil).head

res2: Int = 1

scala> HNil.head

<console>:15: error: could not find implicit value for parameter

c: shapeless.ops.hlist.IsHCons[shapeless.HNil.type]

HNil.head

Coproduct

Coproduct: Implementation

trait Coproduct

trait :+:[+H, +T <: Coproduct] extends

case class Inl[+H, +T <: Coproduct](head : H) extends :+:[H, T]

case class Inr[+H, +T <: Coproduct](tail : T) extends :+:[H, T]

trait CNil extends Coproduct

Shapeless Operations

Shapeless Operations

•Data types (HList, Coproduct etc) reside under the shapeless package.•Operations on these data types are provided by type

classes under shapeless.ops package.•Syntax available via rich wrappers under the shapeless.syntax package.•Companion objects of data types provide implicit

conversions to the rich wrappers.•Rich wrappers delegate to operation type classes.

Shapeless Operations: HList companion

object HList {

import syntax.HListOps

implicit def hlistOps[L <: HList](l: L): HListOps[L] = new HListOps(l)

}

Shapeless Operations: HList Syntax

final class HListOps[L <: HList](l : L) {

def head(implicit c: IsHCons[L]): c.H = c.head(l)

def tail(implicit c: IsHCons[L]): c.T = c.tail(l

}

Shapeless Operations: HList Type classes

object hlist {

trait IsHCons[L <: HList] {

type H

type T <: HList

def head(l: L): H

def tail(l: L): T

def cons(h: H, t: T): L

}

object IsHCons { /*...*/ }

}

Generic

Generic – Motivation

•HLists and Coproducts are another way to express case classes and supertypes.•They provide lost of useful collections operations.•Can we apply these operations to case classes or

supertypes?•Can we define operations applicable to all case

classes or supertypes? E.g. convert any case class to CSV string without defining the logic for each case class?

Generic: Implementationtrait Generic[T] {

type Repr

def to(t : T) : Repr

def from(r : Repr) : T

}

object Generic {

type Aux[T, Repr0] = Generic[T] { type Repr = Repr0 }

def apply[T](implicit gen: Generic[T]): Aux[T, gen.Repr] = gen

implicit def materialize[T, R]: Aux[T, R] =

macro GenericMacros.materialize[T, R]

}

Live Example: Converting an electronic store’s database to

CSV

Q&A

Recommended