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

Introduction to Shapeless

Introduction to Shapeless

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

Nigel Warren

March 17, 2015
Tweet

More Decks by Nigel Warren

Other Decks in Programming

Transcript

  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. ?