Skip to content

Instantly share code, notes, and snippets.

@ailiev
Created August 18, 2012 19:15
Show Gist options
  • Save ailiev/3389162 to your computer and use it in GitHub Desktop.
Save ailiev/3389162 to your computer and use it in GitHub Desktop.
Modified shapeless SYB example
/*
* Copyright (c) 2012 Miles Sabin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package shapeless.examples
/*
* Examples of Scrap Your Boilerplate in action
*
* @author Miles Sabin
*/
object SybClassExamples2 extends App {
import shapeless._
import Poly._
import SybClass._
// Example taken from the original SYB paper:
// "Scrap your boilerplate: a practical approach to generic programming", Ralf Laemmel, Simon Peyton Jones
// http://research.microsoft.com/en-us/um/people/simonpj/papers/hmap/
case class Company(depts : List[Dept])
case class Dept(name : Name, manager : Manager, subunits : List[Employee]) // yes, I know the subunits could also be other Dept's, but let's go with this for simplicity.
sealed trait Employee
case class Regular(person : Person, salary : Salary, rank : Int) extends Employee
case class Contractor(person : Person, hourly : Salary) extends Employee
case class Person(name : Name, address : Address)
case class Salary(salary : Double)
type Manager = Employee
type Name = String
type Address = String
/*
implicit def companyIso = Iso.hlist(Company.apply _, Company.unapply _)
implicit def deptIso = Iso.hlist(Dept.apply _, Dept.unapply _)
implicit val regularIso = Iso.hlist(Regular.apply _, Regular.unapply _)
implicit val contactorIso = Iso.hlist(Contractor.apply _, Contractor.unapply _)
implicit val personIso = Iso.hlist(Person.apply _, Person.unapply _)
implicit val salaryIso = Iso.hlist(Salary.apply _, Salary.unapply _)
*/
/*
// The HListIso definitions for each case class above replace this manually
// written SYB boilerplate
implicit def companyDataT[F <: Poly, D <: HList](implicit fd : HomAux[F, D]) =
new DataT[F, Company[D]] {
def gmapT(c : Company[D]) = c match {
case Company(depts) => Company(fd(depts))
}
}
implicit def deptDataT[F <: Poly, S <: HList]
(implicit fn : HomAux[F, Name], fm : HomAux[F, Manager], fs : HomAux[F, S]) =
new DataT[F, Dept[S]] {
def gmapT(d : Dept[S]) = d match {
case Dept(name, manager, subunits) => Dept(fn(name), fm(manager), fs(subunits))
}
}
implicit def employeeDataT[F <: Poly](implicit fp : HomAux[F, Person], fs : HomAux[F, Salary]) =
new DataT[F, Employee] {
def gmapT(e : Employee) = e match {
case Employee(person, salary) => Employee(fp(person), fs(salary))
}
}
implicit def personDataT[F <: Poly](implicit fn : HomAux[F, Name], fa : HomAux[F, Address]) =
new DataT[F, Person] {
def gmapT(p : Person) = p match {
case Person(name, address) => Person(fn(name), fa(address))
}
}
implicit def salaryDataT[F <: Poly](implicit fs : HomAux[F, Double]) =
new DataT[F, Salary] {
def gmapT(s : Salary) = s match {
case Salary(salary) => Salary(fs(salary))
}
}
*/
object raise extends Poly1 {
implicit def apply[T] = at[T](t => t)
implicit def caseDouble = at[Double](_*1.1)
}
val beforeRaise =
Company(
List(
Dept("Research",
Regular(Person("Ralf", "Amsterdam"), Salary(8000), 4),
List(Regular(Person("Joost", "Amsterdam"), Salary(1000), 7),
Contractor(Person("Marlow", "Cambridge"), Salary(2000))
)
),
Dept("Strategy",
Contractor(Person("Blair", "London"), Salary(100000)),
Nil
)
)
)
println(beforeRaise)
/* Output:
* Company(
* Dept(
* Research,Employee(Person(Ralf,Amsterdam),Salary(8000.0)),
* Employee(Person(Joost,Amsterdam),Salary(1000.0)) ::
* Employee(Person(Marlow,Cambridge),Salary(2000.0)) :: HNil) ::
* Dept(Strategy,Employee(Person(Blair,London),Salary(100000.0)),HNil) :: HNil)
*/
// Compute a new company structure with all salaries increased by 10%
val afterRaise = everywhere(raise)(beforeRaise)
println(afterRaise)
/* Output:
* Company(
* Dept(
* Research,Employee(Person(Ralf,Amsterdam),Salary(8800.0)),
* Employee(Person(Joost,Amsterdam),Salary(1100.0)) ::
* Employee(Person(Marlow,Cambridge),Salary(2200.0)) :: HNil) ::
* Dept(Strategy,Employee(Person(Blair,London),Salary(110000)),HNil) :: HNil)}
*
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment