trait Obs[+A] { def value: A } object Obs { import shapeless._, poly._, ops.hlist.Mapper, ops.function.FnToProduct object values extends (Obs ~> Id) { def apply[T](t: Obs[T]) = t.value } def calculate[T, V <: HList, L <: HList, F, Z](obss: T)(f: F)(implicit gen: Generic.Aux[T, L], mapper: Mapper.Aux[values.type, L, V], ftp: FnToProduct.Aux[F, V => Z] ): Z = ftp(f)(mapper.apply(gen.to(obss))) } object ObsExample { import Obs._ val obs1: Obs[Double] = new Obs[Double] { val value = 10.0 } val obs2: Obs[Option[Int]] = new Obs[Option[Int]] { val value = Some(1) } def func(d: Double, i: Option[Int]) = d + i.getOrElse(0).toDouble println(calculate(obs1, obs2)(func _)) }