Created
August 22, 2016 14:56
-
-
Save n4to4/0997a4b422a1c4c99a8cd96df3d8f00c to your computer and use it in GitHub Desktop.
ScalaExercisesShapeless
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import shapeless._ | |
import scala.language.implicitConversions | |
// object Main extends App { | |
// } | |
object HeterogenousLists extends App { | |
import poly._ | |
object choose extends (Set ~> Option) { | |
def apply[T](s: Set[T]) = s.headOption | |
} | |
val sets = Set(1) :: Set("foo") :: HNil | |
val opts = sets map choose | |
assert(opts == Some(1) :: Some("foo") :: HNil) | |
import poly.identity | |
val l = (23 :: "foo" :: HNil) :: HNil :: (true :: HNil) :: HNil | |
assert((l flatMap identity) == (23 :: "foo" :: true :: HNil)) | |
} | |
object PolymorphicFunctionValues { | |
import poly._ | |
object choose extends (Set ~> Option) { | |
def apply[T](s: Set[T]) = s.headOption | |
} | |
assert(choose(Set(1, 2, 3)) == Some(1)) | |
assert(choose(Set('a', 'b', 'c')) == Some('a')) | |
def pairApply(f: Set ~> Option) = (f(Set(1, 2, 3)), f(Set('a', 'b', 'c'))) | |
assert(pairApply(choose) == ((Some(1), Some('a')))) | |
assert((List(Set(1, 2, 3), Set(2, 4, 6)) map choose) == (List(Some(1), Some(2)))) | |
object size extends Poly1 { | |
implicit def caseInt = at[Int](x => 1) | |
implicit def caseString = at[String](_.length) | |
implicit def caseTuple[T, U](implicit st: Case.Aux[T, Int], su: Case.Aux[U, Int]) = | |
at[(T, U)](t => size(t._1) + size(t._2)) | |
} | |
assert(size(23) == 1) | |
assert(size("foo") == 3) | |
assert(size((23, "foo")) == 4) | |
assert(size(((23, "foo"), 13)) == 5) | |
} | |
object TypeSafeCast { | |
import syntax.typeable._ | |
val l: Any = List(Vector("foo", "bar", "baz"), Vector("wibble")) | |
assert(l.cast[List[Vector[String]]] == Some(l)) | |
assert(l.cast[List[Vector[Int]]] == None) | |
assert(l.cast[List[List[String]]] == None) | |
val `List[String]` = TypeCase[List[String]] | |
val `List[Int]` = TypeCase[List[Int]] | |
val ll = List(1, 2, 3) | |
val result = (ll: Any) match { | |
case `List[String]`(List(s, _*)) => s.length | |
case `List[Int]`(List(i, _*)) => i + 1 | |
} | |
assert(result == 2) | |
} | |
object Lazy { | |
sealed trait List[+T] | |
case class Cons[T](hd: T, tl: List[T]) extends List[T] | |
sealed trait Nil extends List[Nothing] | |
case object Nil extends Nil | |
trait Show[T] { | |
def apply(t: T): String | |
} | |
object Show { | |
// Base case for Int | |
implicit def showInt: Show[Int] = new Show[Int] { | |
def apply(t: Int) = t.toString | |
} | |
// Base case for Nil | |
implicit def showNil: Show[Nil] = new Show[Nil] { | |
def apply(t: Nil) = "Nil" | |
} | |
// Case for Cons[T]: note (mutually) recursive implicit argument referencing Show[List[T]] | |
implicit def showCons[T](implicit st: Lazy[Show[T]], sl: Lazy[Show[List[T]]]): Show[Cons[T]] = new Show[Cons[T]] { | |
def apply(t: Cons[T]) = s"Cons(${show(t.hd)(st.value)}, ${show(t.tl)(sl.value)})" | |
} | |
// Case for List[T]: note (mutually) recursive implicit argument referencing Show[Cons[T]] | |
implicit def showList[T](implicit sc: Lazy[Show[Cons[T]]]): Show[List[T]] = new Show[List[T]] { | |
def apply(t: List[T]) = t match { | |
case n: Nil => show(n) | |
case c: Cons[T] => show(c)(sc.value) | |
} | |
} | |
} | |
def show[T](t: T)(implicit s: Show[T]) = s(t) | |
val l: List[Int] = Cons(1, Cons(2, Cons(3, Nil))) | |
assert(show(l) == "Cons(1, Cons(2, Cons(3, Nil)))") | |
} | |
object AutoTypeclassDerivation { | |
trait Monoid[T] { | |
def zero: T | |
def append(a: T, b: T): T | |
} | |
object Monoid extends ProductTypeClassCompanion[Monoid] { | |
def mzero[T](implicit mt: Monoid[T]) = mt.zero | |
implicit def booleanMonoid: Monoid[Boolean] = new Monoid[Boolean] { | |
def zero = false | |
def append(a: Boolean, b: Boolean) = a || b | |
} | |
implicit def intMonoid: Monoid[Int] = new Monoid[Int] { | |
def zero = 0 | |
def append(a: Int, b: Int) = a + b | |
} | |
implicit def doubleMonoid: Monoid[Double] = new Monoid[Double] { | |
def zero = 0.0 | |
def append(a: Double, b: Double) = a + b | |
} | |
implicit def stringMonoid: Monoid[String] = new Monoid[String] { | |
def zero = "" | |
def append(a: String, b: String) = a + b | |
} | |
object typeClass extends ProductTypeClass[Monoid] { | |
def emptyProduct = new Monoid[HNil] { | |
def zero = HNil | |
def append(a: HNil, b: HNil) = HNil | |
} | |
def product[F, T <: HList](mh: Monoid[F], mt: Monoid[T]) = new Monoid[F :: T] { | |
def zero = mh.zero :: mt.zero | |
def append(a: F :: T, b: F :: T) = mh.append(a.head, b.head) :: mt.append(a.tail, b.tail) | |
} | |
def project[F, G](instance: => Monoid[G], to: F => G, from: G => F) = new Monoid[F] { | |
def zero = from(instance.zero) | |
def append(a: F, b: F) = from(instance.append(to(a), to(b))) | |
} | |
} | |
} | |
trait MonoidSyntax[T] { | |
def |+|(b: T): T | |
} | |
object MonoidSyntax { | |
implicit def monoidSyntax[T](a: T)(implicit mt: Monoid[T]): MonoidSyntax[T] = new MonoidSyntax[T] { | |
def |+|(b: T) = mt.append(a, b) | |
} | |
} | |
// A pair of arbitrary case classes | |
case class Foo(i: Int, s: String) | |
case class Bar(b: Boolean, s: String, d: Double) | |
import MonoidSyntax._ | |
import Monoid.typeClass._ | |
val fooCombined = Foo(13, "foo") |+| Foo(23, "bar") | |
assert(fooCombined == Foo(36, "foobar")) | |
val barCombined = Bar(true, "foo", 1.0) |+| Bar(false, "bar", 3.0) | |
assert(barCombined == Bar(true, "foobar", 4.0)) | |
} | |
object Lenses { | |
// A pair of ordinary case classes ... | |
case class Address(street: String, city: String, postcode: String) | |
case class Person(name: String, age: Int, address: Address) | |
// Some lenses over Person/Address ... | |
val nameLens = lens[Person] >> 'name | |
val ageLens = lens[Person] >> 'age | |
val addressLens = lens[Person] >> 'address | |
val streetLens = lens[Person] >> 'address >> 'street | |
val cityLens = lens[Person] >> 'address >> 'city | |
val postcodeLens = lens[Person] >> 'address >> 'postcode | |
val person = Person("Joe Grey", 37, Address("Southover Street", "Brighton", "BN2 9UA")) | |
assert(ageLens.get(person) == 37) | |
val updatedPerson = ageLens.set(person)(38) | |
assert(updatedPerson.age == 38) | |
val updatedPerson2 = ageLens.modify(person)(_ + 1) | |
assert(updatedPerson2.age == 38) | |
assert(streetLens.get(person) == "Southover Street") | |
val updatedPerson3 = streetLens.set(person)("Montpelier Road") | |
assert(updatedPerson3.address.street == "Montpelier Road") | |
} | |
object MainGeneric { | |
case class Foo(i: Int, s: String, b: Boolean) | |
val fooGen = Generic[Foo] | |
val foo = Foo(23, "foo", true) | |
val l = fooGen.to(foo) | |
assert(l == 23 :: "foo" :: true :: HNil) | |
val r = 13 :: l.tail | |
val newFoo = fooGen.from(r) | |
assert(newFoo.i == 13) | |
import poly._ | |
sealed trait Tree[T] | |
case class Leaf[T](t: T) extends Tree[T] | |
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T] | |
object inc extends -> ((i: Int) => i + 1) | |
val tree: Tree[Int] = | |
Node( | |
Leaf(1), | |
Node( | |
Leaf(2), | |
Leaf(3) | |
) | |
) | |
assert(everywhere(inc)(tree) == Node( | |
Leaf(2), | |
Node( | |
Leaf(3), | |
Leaf(4) | |
) | |
)) | |
import record._ | |
case class Book(author: String, title: String, id: Int, price: Double) | |
val bookGen = LabelledGeneric[Book] | |
val tapl = Book("Benjamin Pierce", "Types and Programming Languages", 262162091, 44.11) | |
val rec = bookGen.to(tapl) | |
assert(rec('price) == 44.11) | |
val updatedBook = bookGen.from(rec.updateWith('price)(_ + 2.0)) | |
assert(updatedBook.price == 46.11) | |
import syntax.singleton._ | |
case class ExtendedBook(author: String, title: String, id: Int, price: Double, inPrint: Boolean) | |
val bookExtGen = LabelledGeneric[ExtendedBook] | |
val extendedBook = bookExtGen.from(rec + ('inPrint ->> true)) | |
assert(extendedBook.inPrint == true) | |
} | |
object Coproducts { | |
import shapeless._, poly._ | |
object sizeM extends Poly1 { | |
implicit def caseInt = at[Int](i => (i, i)) | |
implicit def caseString = at[String](s => (s, s.length)) | |
implicit def caseBoolean = at[Boolean](b => (b, 1)) | |
} | |
type ISB = Int :+: String :+: Boolean :+: CNil | |
val isb = Coproduct[ISB]("foo") | |
val m = isb map sizeM | |
assert(m.select[(String, Int)] == Some(("foo", 3))) | |
import record._, union._, syntax.singleton._ | |
type U = Union.`'i -> String, 's -> String, 'b -> Boolean`.T | |
val u = Coproduct[U]('s ->> "foo") | |
assert(u.get('i) == None) | |
assert(u.get('s) == Some("foo")) | |
assert(u.get('b) == None) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment