Я не думаю, что это напрямую возможно с использованием некоторых классов типов в Shapeless, но можно сделать аналогичное для функции типа (T0, T1, ...) => R
:
implicit class HListOps[L <: HList](value: L) {
def fold[R, F](folder: F)(implicit ftp: FnToProduct.Aux[F, L => R]): R = {
ftp(folder).apply(value)
}
}
(1 :: "a" :: HNil).fold((x: Int, y: String) => y + x)
К сожалению, вы все ещедолжны явно указать параметры для типа функции. теоретически можно определить класс расширения для этого:
implicit class HListOps2[L <: HList, F, R](value: L)(implicit ftp: FnToProduct.Aux[F, L => R]) {
def fold(folder: F): R = ftp(folder).apply(value)
}
Это, однако, потребует от вас знать тип результата "заранее", что довольно неэргономично (и на самом деле не будет работать с приведенным выше определением, но можно заставить его работать с немного большим количеством кода).
Вы можете преодолеть последнюю проблему, потребовав вместо функции принимать кортеж:
implicit class HListOps3[L <: HList, T](value: L)(implicit tup: Tupler.Aux[L, T]) {
def fold[R](folder: T => R): R = folder(tup(value))
}
(1 :: "a" :: HNil).fold { case (x, y) => y + x }
Таким образом, вам не нужно указывать типы аргументов для функции, скорее, сама функция должна принимать кортеж, что также немного эргономично, потому что вам придется использовать частичную функциюсинтаксис для распаковки аргументов из аргумента кортежа.