hl = 1 :: "String" :: 2.0 :: HNil val (a, b, c) = t val x :: y :: z :: HNil = hl t match { case (1, s, _) => ... } hl match { case 1 :: s :: _ :: HNil => ... }
=> ... // matches if first element 1, regardless the size of the list // and binds the tail to `rest` case x :: y :: HNil => ... // matches when it is a pair // etc. }
1 :: "String" :: 2.0 :: HNil val t : (Int, String, Double) = hl.tupled aTuple.productElements match { case a :: b :: HNil => ... } case class Person(name: String, age: Int) Person("John", 40).productElements match { case name :: age :: HNil => ... }
= Generic[Tuple2[String,Int]] val johnTuple = ("John", 40) val hl: String :: Int :: HNil = gp.to(johnTuple) val tp: Tuple2[String,Int] = gp.from(hl) assert( johnTuple == tp ) In fact, the t.productElements method is really short-hand syntax for the code snippet above.
into a unary function of one K-tuple argument. For instance: val f = (s: String, i: Int) => s"$s $i" val ft: Tuple2[String, Int] => String = f.tupled tuples are fixed-size! But with HLists... import syntax.std.function._ import ops.function._ val fhl: String::Int::HNil => String = f.toProduct
relation holds ?- grandchild(X, Y). X = john Y = tom % find the john's grandchildren ?- grandchild(john, Y). Y = tom % find tom's grandparents ?- grandchild(X, tom). X = john
predicate holds ▸ when one such an object instance provides methods, then it is called a typeclass. ▸ Generic[P] provides the methods to(P) and from(HList).
For instance, Generic.Aux is defined in the companion object of Generic object Generic { type Aux[P,L] = Generic[P] { type Out = L } ... } trait Generic[P] { type Out }
system ▸ Mark Harrah's series on type-level programming ▸ Stefan Zeiger's slides on Type-level Computations ▸ Sam Halliday's Shapeless For Mortals ▸ Miles Sabin's introductory talks ▸ Why is the Aux technique required for type-level computations? on StackOverflow ▸ Shapeless Wiki ▸ Shapeless Examples ▸ Eugene Yokota's “Herding Cats”