如何将任意函数列表应用于任意值?
How can I apply an HList of arbitrary functions to an arbitrary value?
我希望能够将 Function1[I, ?]
的任意列表应用于任意输入 I
。这是我目前所拥有的:
type StringInputFunction[T] = Function[String, T]
val strLen: String => Int = _.length
val strRev: String => String = _.reverse
val functions = strLen :: strRev :: HNil
val expected = 4 :: "evif" :: HNil
object applyTo5 extends (StringInputFunction ~> Id) {
override def apply[T](f: StringInputFunction[T]): Id[T] = f("five")
}
def applyFunctionsTo5[FH <: HList, OH <: HList](fs: FH)
(implicit constrain: UnaryTCConstraint[FH, StringInputFunction],
mapper: Mapper.Aux[applyTo5.type, FH, OH]): mapper.Out = {
fs.map(applyTo5)
}
applyFunctionsTo5(functions) shouldBe expected
class ApplyTo(string: String) extends (StringInputFunction ~> Id) {
override def apply[T](f: StringInputFunction[T]): Id[T] = f(string)
}
def applyFunctionsTo[FH <: HList, OH <: HList]
(fs: FH, input: String)
(implicit constrain: UnaryTCConstraint[FH, StringInputFunction],
mapper: Mapper.Aux[ApplyTo, FH, OH]): mapper.Out = {
val applyTo = new ApplyTo(input)
fs.map(applyTo)
}
applyFunctionsTo(functions, "five") shouldBe expected
这导致编译错误:
ShapelessSpec.scala:81: could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[applyTo.type,FH]
fs.map(applyTo)
ShapelessSpec.scala:83: could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper.Aux[ApplyTo,shapeless.::[String => Int,shapeless.::[String => String,shapeless.HNil]],OH]
applyFunctionsTo(functions, "five") shouldBe expected
- 我如何解决这个问题以使用任何
String
输入?
- 我能否进一步更改泛型化以使用任何输入类型
T
?
我在想我以前做过这个确切的操作,并且能够找到几年前的 this gist。总结一下我的示例,您可以仅使用 Shapeless 已经提供的操作来很好地完成此操作,其方式看起来很像您在值级别对普通列表执行类似操作的方式。假设您有以下设置:
import shapeless.{ ::, HNil }
val strLen: String => Int = _.length
val strRev: String => String = _.reverse
val functions = strLen :: strRev :: HNil
那你可以这么写:
scala> functions.zipApply(functions.mapConst("five"))
res0: Int :: String :: shapeless.HNil = 4 :: evif :: HNil
或者这个:
scala> def foo(in: String) = functions.zipApply(functions.mapConst(in))
foo: (in: String)Int :: String :: shapeless.HNil
scala> foo("six")
res1: Int :: String :: shapeless.HNil = 3 :: xis :: HNil
这将适用于应用于该特定类型的特定类型的任何 hlist 函数。
要点给出了一些替代方法,但 zipApply
加上 mapConst
对我来说是目前为止最好的方法。
我希望能够将 Function1[I, ?]
的任意列表应用于任意输入 I
。这是我目前所拥有的:
type StringInputFunction[T] = Function[String, T]
val strLen: String => Int = _.length
val strRev: String => String = _.reverse
val functions = strLen :: strRev :: HNil
val expected = 4 :: "evif" :: HNil
object applyTo5 extends (StringInputFunction ~> Id) {
override def apply[T](f: StringInputFunction[T]): Id[T] = f("five")
}
def applyFunctionsTo5[FH <: HList, OH <: HList](fs: FH)
(implicit constrain: UnaryTCConstraint[FH, StringInputFunction],
mapper: Mapper.Aux[applyTo5.type, FH, OH]): mapper.Out = {
fs.map(applyTo5)
}
applyFunctionsTo5(functions) shouldBe expected
class ApplyTo(string: String) extends (StringInputFunction ~> Id) {
override def apply[T](f: StringInputFunction[T]): Id[T] = f(string)
}
def applyFunctionsTo[FH <: HList, OH <: HList]
(fs: FH, input: String)
(implicit constrain: UnaryTCConstraint[FH, StringInputFunction],
mapper: Mapper.Aux[ApplyTo, FH, OH]): mapper.Out = {
val applyTo = new ApplyTo(input)
fs.map(applyTo)
}
applyFunctionsTo(functions, "five") shouldBe expected
这导致编译错误:
ShapelessSpec.scala:81: could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper[applyTo.type,FH]
fs.map(applyTo)
ShapelessSpec.scala:83: could not find implicit value for parameter mapper: shapeless.ops.hlist.Mapper.Aux[ApplyTo,shapeless.::[String => Int,shapeless.::[String => String,shapeless.HNil]],OH]
applyFunctionsTo(functions, "five") shouldBe expected
- 我如何解决这个问题以使用任何
String
输入? - 我能否进一步更改泛型化以使用任何输入类型
T
?
我在想我以前做过这个确切的操作,并且能够找到几年前的 this gist。总结一下我的示例,您可以仅使用 Shapeless 已经提供的操作来很好地完成此操作,其方式看起来很像您在值级别对普通列表执行类似操作的方式。假设您有以下设置:
import shapeless.{ ::, HNil }
val strLen: String => Int = _.length
val strRev: String => String = _.reverse
val functions = strLen :: strRev :: HNil
那你可以这么写:
scala> functions.zipApply(functions.mapConst("five"))
res0: Int :: String :: shapeless.HNil = 4 :: evif :: HNil
或者这个:
scala> def foo(in: String) = functions.zipApply(functions.mapConst(in))
foo: (in: String)Int :: String :: shapeless.HNil
scala> foo("six")
res1: Int :: String :: shapeless.HNil = 3 :: xis :: HNil
这将适用于应用于该特定类型的特定类型的任何 hlist 函数。
要点给出了一些替代方法,但 zipApply
加上 mapConst
对我来说是目前为止最好的方法。