Skip to content

Instantly share code, notes, and snippets.

@milessabin
Last active August 29, 2015 14:18
Show Gist options
  • Save milessabin/63de4353d43721c93677 to your computer and use it in GitHub Desktop.
Save milessabin/63de4353d43721c93677 to your computer and use it in GitHub Desktop.
Function type inference not too shabby ...
import shapeless._
import ops.function._
// Contravariant version of shapeless's FnToProduct
trait ContraFnToProduct[-F] {
type Out
def apply(f: F): Out
}
object ContraFnToProduct {
type Aux[F, Out0] = ContraFnToProduct[F] { type Out = Out0 }
implicit def fnp2[A, B, C, Res]: Aux[(A, B, C) => Res, (A :: B :: C :: HNil) => Res] =
new ContraFnToProduct[(A, B, C) => Res] {
type Out = (A :: B :: C :: HNil) => Res
def apply(f: (A, B, C) => Res): Out = (l: A :: B :: C :: HNil) => f(l.head, l.tail.head, l.tail.tail.head)
}
}
object Test extends App {
class HListSyntax[A <: HList, F <: AnyRef](a: A) {
def $$[U](f: F)(implicit cftp: ContraFnToProduct.Aux[f.type, A => U]): U = cftp(f)(a)
}
implicit def mkSyntax[A <: HList, F <: AnyRef](a: A)
(implicit ffp: FnFromProduct.Aux[A => Any, F]): HListSyntax[A, F] =
new HListSyntax[A, F](a)
implicit def mkSyntax[P, A <: HList, F <: AnyRef](p: P)
(implicit gen: Generic.Aux[P, A], ffp: FnFromProduct.Aux[A => Any, F]): HListSyntax[A, F] =
new HListSyntax[A, F](gen.to(p))
val res0 = (2 :: "a" :: 1.3 :: HNil) $$ ((i, s, d) => (s * i, d * i)) // Function argument types inferred
assert((res0: (String, Double)) == ("aa", 2.6))
// Tuples
val res1 = (2, "a", 1.3) $$ ((i, s, d) => (s * i, d * i)) // Function argument types inferred
assert((res1: (String, Double)) == ("aa", 2.6))
// Types (eg. case classes) with a Generic instance
case class Foo(i: Int, s: String, d: Double)
val res2 = Foo(2, "a", 1.3) $$ ((i, s, d) => (s * i, d * i)) // Function argument types inferred
assert((res2: (String, Double)) == ("aa", 2.6))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment