是否有一种优雅的解决方案可以以某种方式清理隐式参数列表,使签名更简洁?我有这样的代码:
import shapeless._
import shapeless.HList._
import shapeless.ops.hlist._
import shapeless.poly._
trait T[I, O] extends (I => O)
trait Validator[P]
object Validator{
def apply[P] = new Validator[P]{}
}
object valid extends Poly1 {
implicit def caseFunction[In, Out] = at[T[In, Out]](f => Validator[In])
}
object isValid extends Poly2 {
implicit def caseFolder[Last, New] = at[Validator[Last], T[Last, New]]{(v, n) => Validator[New]}
}
object mkTask extends Poly1 {
implicit def caseT[In, Out] = at[T[In, Out]](x => x)
implicit def caseFunction[In, Out] = at[In => Out](f => T[In, Out](f))
}
object Pipeline {
def apply[H <: HList, Head, Res, MapRes <: HList](steps: H)
(implicit
mapper: Mapper.Aux[mkTask.type,H, MapRes],
isCons: IsHCons.Aux[MapRes, Head, _],
cse: Case.Aux[valid.type, Head :: HNil, Res],
folder: LeftFolder[MapRes, Res, isValid.type]
): MapRes = {
val wrapped = (steps map mkTask)
wrapped.foldLeft(valid(wrapped.head))(isValid)
wrapped
}
}
// just for sugar
def T[I, O](f: I => O) = new T[I, O] {
override def apply(v1: I): O = f(v1)
}
Pipeline(T((x:Int) => "a") :: T((x:String) => 5) :: HNil) // compiles OK
Pipeline(((x:Int) => "a") :: ((x:String) => 5) :: HNil) // compiles OK
// Pipeline("abc" :: "5" :: HNil) // doesn't compile
// can we show an error like "Parameters are not of shape ( _ => _ ) or T[_,_]"?
// Pipeline(T((x: Int) => "a") :: T((x: Long) => 4) :: HNil) // doesn't compile
// can we show an error like "Sequentiality constraint failed"?
而且我还想添加一些库功能所需的隐式参数(到 Pipeline.apply 方法),但签名已经很大了。我担心其他开发人员易于理解 - 是否有“最佳实践”方式来构建这些参数?
编辑:我的意思是隐式参数属于不同的类别。在此示例中:mapper
确保正确的内容类型,isCons
并cse
确保folder
对输入的顺序约束,并且我想添加表示业务逻辑“可行性”的隐含。它们应该如何分组,是否可以以可读的格式进行?
Edit2:是否有可能以某种方式提醒图书馆的用户,关于违反了哪个约束?例如,HList 中的类型是错误的,或者没有保持顺序约束,或者他缺乏适当的“业务逻辑”隐含?