Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introduction to Shapeless

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

Introduction to Shapeless

An introduction to using the Shapeless Library for the Scala programming language

Nigel Warren

March 17, 2015

Transcript

20 slides
  1. Shapeless “Since  [2011]  Shapeless  has  evolved  from  being  a  

    resolutely   experimental   project   into   library  which,   while   s+ll   tes+ng   the   limits   of   what's   possible   in   Scala,   is   being   used  widely   in   produc+on   systems   wherever   there   are   ari+es   to   be   abstracted   over   and  boilerplate  to  be  scrapped.”   hIps:/ /github.com/milessabin/shapeless
  2. Example:  Solvers In  our  case  :   AIempt  to  find

     the  result  (root),  as  the  nearest  value   to   0,   of   a   func+on   by   repeatedly   supplying   varying     parameter  values  to  the  func+on.     Parameters  values  range    0.0  -­‐>  1.0   Parameter  arity  1  ~>  10   hIp:/ /en.wikipedia.org/wiki/Solver
  3. Target  func+on     def func(a : Double, b :

    Double, c : Double) : Double =
 (a - 0.2) + (b - 0.5) + (c - 0.7)
 The   underlying  Java   port   of   solver   uses  Arrays   to   express  the  root  hints,  the  func+on  parameters  and   the   parameters   that   get   nearest   to   the   func+ons   root.   def solveInternal( hint : Array[Double], func : (Array[Double]) => Double) : Array[Double]
  4. Bug  !   The  ‘hint’  array  was  arity  3  and

     Func+on  was  arity   4.   Need   to   ‘lock   together’   the   arity   of   the   hint,   func+on  parameters,  and  resul+ng  array.     Catch  all  of  these  errors  at  compile  +me.     Use   the   compiler   to   eliminate   all   of   the   ‘arity   mismatch’  test  cases.  
  5. First  ‘Solu+on’     def solve( hint : Double, func

    : (Double) => Double) : Double
 
 def solve( hint : (Double, Double), 
 func : (Double, Double) => Double) 
 : (Double, Double)
 
 def solve( hint : (Double, Double, Double),
 func : (Double, Double, Double) => Double )
 : (Double, Double, Double)
 
 def solve( hint : (Double, Double, Double, Double),
 func : (Double, Double, Double, Double) => Double)
 : (Double, Double, Double, Double)
  6. But  …   What  if  we  could  encode  Natural  numbers

     into  the   type  system  and  use  these  to  constrain  the  size  of   the  Arrays.   Shapeless  Has  …   • ‘Nat’  -­‐  natural  number  type  encodings     •  ‘Sized’  -­‐  compile  +me  sized  collec+ons
  7. import shapeless._ val hints = Sized(0.5, 0.5, 0.5) def toBeSolved(params

    : Sized[IndexedSeq[Double], nat._3]) 
 : Double = {
 val a = params at Nat(0)
 import nat._
 val b = params at _1
 val c = params(_2)
 (a - 0.2) + (b - 0.5) + (c - 0.7)
 } val s = solve( hints, toBeSolved )
  8. import shapeless._ val hints = Sized(0.5, 0.5, 0.5, 0.5) def

    toBeSolved(params : Sized[IndexedSeq[Double], nat._3]) 
 : Double = {
 ??? } val s = solve( hints, toBeSolved ) [error] Solver.scala:75: type mismatch; [error] found:shapeless.Sized[IndexedSeq[Double],shapeless.nat._4] [error] required: shapeless.Sized[IndexedSeq[Double], … ]
  9. import shapeless._ import nat._ val hints = Sized(0.5, 0.5, 0.5)

    def toBeSolved(params : Sized[IndexedSeq[Double], _3]) 
 : Double = {
 val (a,b,c) = params.toHList.tupled
 (a - 0.2) + (b - 0.5) + (c - 0.7)
 } val s = solve( hints, toBeSolved )
  10. HLists Tuples     • Fixed  length  sequence  of  dis+nct

     types   Collec+ons     • Varying   length   sequence   of   elements   of   the   same   types   HLists   • Varying  length  sequence  of  elements  of  dis+nct  types
  11. Polymorphic  Func+on  Values How  do  we  map,  fold  etc  over

     an  HList  using,  and   transforming  /  preserving  element  types  ?
  12. object size extends Poly1 {
 implicit def caseInt = at[Int](

    x => 4 )
 implicit def caseString = at[String]( 2 * _.length + 16)
 implicit def caseBoolean = at[Boolean] ( x => 4 )
 } val hl = 23 :: "Ola" :: true :: HNil
 val sum = hl.map(size).toList.sum object rotator extends Poly1 {
 implicit def caseInt = at[Int]( x => true )
 implicit def caseString = at[String]( x => 1)
 implicit def caseBoolean = at[Boolean] ( x => "True" )
 }
  13. HLists  in  Use Mathias  Doenitz  has  used  HLists  in  Spray

     Rou+ng   and  Parboiled  2.   In  parsing  the  DSLs  parboiled2  pushes  values  onto   an   HList   stack   and   pops   them   as   required,   as   parameter  to  func+ons  for  example.   hIps:/ /github.com/sirthias/parboiled2
  14. HLists  in  Use Joni   Freeman's   “sqltyped”   library

      makes   extensive   use  of  shapeless  extensible  records.   hIps:/ /github.com/jonifreeman/sqltyped   also  see  ‘doobie’  project.
  15. HLists  in  Use Scodec  is  a  a  combinator  library  for

     purely  func+on   encoding/decoding   of   binary   data.   Uses   HLists   to   do  automa+c  case  class  binding.   case class Point(x: Int, y: Int, z: Int) val pointCodec = (int8 :: int8 :: int8).as[Point]) hIps:/ /github.com/scodec/scodec
  16. ?

More Decks by Nigel Warren

Other Decks in Programming