1)从你的函数中提取类型信息到HList
(从shapeless)Ts
和类型参数Res
。
对于Int => String => Long => String
Ts
isInt :: String :: Long :: HNil
和Res
is String
:
import shapeless.{HList, HNil, ::}
trait TypeExtractorAux[A, R, Ts <: HList, Res]
trait LowPriorityTypeExtractorAux{
implicit def apply1[A, R]: TypeExtractorAux[A, R, A :: HNil, R] = new TypeExtractorAux[A, R, A :: HNil, R]{}
}
object TypeExtractorAux extends LowPriorityTypeExtractorAux{
implicit def applyN[A1, A2, R, TsNext <: HList, Res](implicit te: TypeExtractorAux[A2, R, TsNext, Res]): TypeExtractorAux[A1, A2 => R, A1 :: TsNext, Res] =
new TypeExtractorAux[A1, A2 => R, A1 :: TsNext, Res]{}
}
2)将咖喱函数转换为Ts => Res
:
trait FunctionConverterAux[Ts <: HList, Res, A, R]{
def apply(f: A => R): Ts => Res
}
object FunctionConverterAux{
implicit def apply1[L, Res]: FunctionConverterAux[L :: HNil, Res, L, Res] =
new FunctionConverterAux[L :: HNil, Res, L, Res]{
def apply(f: L => Res): L :: HNil => Res = hl => f(hl.head)
}
implicit def applyN[L1, L2, Rt <: HList, Res, R](implicit fc: FunctionConverterAux[L2 :: Rt, Res, L2, R]): FunctionConverterAux[L1 :: L2 :: Rt, Res, L1, L2 => R] =
new FunctionConverterAux[L1 :: L2 :: Rt, Res, L1, L2 => R]{
def apply(f: L1 => L2 => R): L1 :: L2 :: Rt => Res = hl => fc(f(hl.head))(hl.tail)
}
}
结果Int => String => Long => String
是Int :: String :: Long :: HNil => String
3)反转Ts
使用shapeless.HList.ReverseAux
并收集所有参数HList
。你会得到Ts
. 然后将您的Ts => Res
函数应用于HList
参数:
trait ArgumentsGetterAux[Prev <: HList, Rest <: HList, NR, Ts, Res]{
def apply(p: Prev, f: Ts => Res): NR
}
object ArgumentsGetterAux{
implicit def applyHNil[Prev <: HList, L, Res]: ArgumentsGetterAux[Prev, L :: HNil, L => Res, L :: Prev, Res] =
new ArgumentsGetterAux[Prev, L :: HNil, L => Res, L :: Prev, Res]{
def apply(p: Prev, f: L :: Prev => Res): L => Res = l => f(l :: p)
}
implicit def applyHList[Prev <: HList, L1, R <: HList, NR, Ts, Res](implicit aga: ArgumentsGetterAux[L1 :: Prev, R, NR, Ts, Res]): ArgumentsGetterAux[Prev, L1 :: R, L1 => NR, Ts, Res] =
new ArgumentsGetterAux[Prev, L1 :: R, L1 => NR, Ts, Res]{
def apply(p: Prev, f: Ts => Res): L1 => NR = l => aga(l :: p, f)
}
}
invert
方法:
import shapeless.HList.ReverseAux
def invert[A, R, Ts <: HList, Res, RevTs <: HList, NR](f: A => R)(
implicit te: TypeExtractorAux[A, R, Ts, Res],
r: ReverseAux[Ts, RevTs],
ag: ArgumentsGetterAux[HNil, RevTs, NR, Ts, Res],
fc: FunctionConverterAux[Ts, Res, A, R]
): NR = ag(HNil, fc(f))
用法:
scala> invert((i: Int) => (s: String) => (l: Long) => s"i: $i; s: $s; l: $l")
res0: Long => (String => (Int => String)) = <function1>
scala> res0(666L)("str")(1)
res1: String = i: 1; s: str; l: 666