记录为参数,组成

Ale*_*ari 5 scala shapeless

编辑:我将问题重新表述为更简单且更少域特定的问题:在下面的代码中,我想实现mplus函数,该函数结合了受特定字段存在约束的两个函数.结果函数应该受到两个字段的存在的约束.谢谢 !

import shapeless._, ops.record.Selector, record._, syntax.singleton._

def requiresIntervalKey[L <: HList](l: L)
                                   (implicit sel: Selector.Aux[L, Witness.`"interval"`.T, Int]): Unit = {
  println(sel(l))
}
def requiresPlatformField[L <: HList](l: L)
                                     (implicit sel: Selector.Aux[L, Witness.`"platform"`.T, String]): Unit = {
  println(sel(l))
}
def mplus = ??? // That is the function I'd like to implement. Eventually it will be the additive operator of a monoid

// needsBothFields: L <: HList -> (implicit) Selector.Aux[L, Witness.`"interval"`.T, Int] -> (implicit) Selector.Aux[L, Witness.`"platform"`.T, String] -> Unit
val needsBothField = mplus(requiresIntervalKey _, requiresIntervalKey _ )

// Usage
requiresIntervalKey(("interval" ->> "a string") :: HNil) // Shoudn't compile, value type is wrong
requiresIntervalKey(("wrongKey" ->> "a string") :: HNil) // Shoudn't compile, "interval" key not provided
requiresIntervalKey(("interval" ->> 42) :: HNil) // Compiles
requiresPlatformField(("platform" ->> "EU") :: HNil) // Compiles
needsBothFields(("interval" ->> 42) :: ("platform" ->> "EU") :: HNil) // Should compile
Run Code Online (Sandbox Code Playgroud)

//上一个问题版本

对于无形和类型级编程来说,我很难实现我的目标并获得清晰的理解.非常感谢您的帮助!

我基本上有几个函数如下所示:

trait PathGenerator[T] {
  def apply(T): Set[Seq[String]]
}

val hourlyIntervalPathGenerator: PathGenerator[Interval] = ???
val constantGenerator: PathGenerator[String] = ???

// A Monoid[PathGenerator]
// an implicit class adding a '/' operator to PathGenerator

// Usage
val hourlyRegionPathGenerator = hourlyIntervalPathGenerator / constantGenerator
val paths = hourlyRegionPathGenerator(StaticIntervals.lastDay, "EU")
Run Code Online (Sandbox Code Playgroud)

现在,当将两个以上的生成器一起添加时,用户必须使用嵌套元组.此外,命名生成器参数对于生成解析器非常有用(例如:cmd-line.)

无形记录似乎非常合适,所以我继续实施以下非工作解决方案:https: //gist.github.com/amazari/911449b55270a5871d14

这个不可构建的代码和我无形的误解产生了几个问题:

  • 从记录中获取字段的值(L26: keys("interval")L35: keys(constant))不会返回预期类型的​​值,即使提供了Witness和选择器也很困难.
  • 在编写其中两个时,我无法提取正确的子记录类型以传递给底层生成器(L52-53.)
  • L69:由于我不明白的原因,所提供的记录与所需的类型不符.

那么,记录是否是实现此用例的正确工具?代码段中未显示从PathPattern的记录形状/模板生成的命令行解析器.

我怎么能强制提供给生成器的记录(简单的或由几个组合产生的)在名称和类型方面具有完全正确的字段?

谢谢你的帮助!

编辑:这一系列问题和Travis Brown的答案非常相关:

将无形可扩展记录 传递给函数 将无形可扩展记录传递给函数(续)将无形可扩展记录传递给函数(永无止境的故事?

Tra*_*own 2

这对于 Shapeless 来说是可能,尽管不完全是您所要求的形式。这是一个简单的例子:

\n\n
import shapeless._, ops.record.Selector, record._, syntax.singleton._\n\nclass UseKey[K <: String, V, R](w: Witness.Aux[K])(f: V => R) extends Poly1 {\n  implicit def onRecord[L <: HList](implicit\n    sel: Selector.Aux[L, K, V]\n  ): Case.Aux[L, R] = at[L](l => f(sel(l)))\n}\n\nclass Combine[P1 <: Poly1, P2 <: Poly1, R1, R2, R](\n  p1: P1,\n  p2: P2\n)(f: (R1, R2) => R) extends Poly1 {\n  implicit def onRecord[L <: HList](implicit\n    c1: p1.Case.Aux[L, R1],\n    c2: p2.Case.Aux[L, R2]\n  ): Case.Aux[L, Unit] = at[L](l => f(c1(l), c2(l)))\n}\n\nclass mplus[P1 <: Poly1, P2 <: Poly1](p1: P1, p2: P2)\n  extends Combine(p1, p2)((_: Unit, _: Unit) => ())\n
Run Code Online (Sandbox Code Playgroud)\n\n

进而:

\n\n
object requiresIntervalKey extends UseKey(Witness("interval"))(\n  (i: Int) => println(i)\n)\n\nobject requiresPlatformField extends UseKey(Witness("platform"))(\n  (s: String) => println(s)\n)\n\nobject needsBothFields extends mplus(requiresIntervalKey, requiresPlatformField)\n
Run Code Online (Sandbox Code Playgroud)\n\n

(作为旁注,我猜你可以直接写UseKey("platform")在这里,但由于某种原因,捕获见证的隐式转换不起作用。幸运的Witness("platform")是,还不错。)

\n\n

接下来展示它的工作原理:

\n\n
scala> import test.illTyped\nimport test.illTyped\n\nscala> illTyped("""requiresIntervalKey("interval" ->> "a string" :: HNil)""")\n\nscala> illTyped("""requiresIntervalKey("wrongKey" ->> "a string" :: HNil)""")\n\nscala> requiresIntervalKey("interval" ->> 42 :: HNil)\n42\n\nscala> requiresPlatformField("platform" ->> "EU" :: HNil)\nEU\n\nscala> needsBothFields("interval" ->> 42 :: "platform" ->> "EU" :: HNil)\n42\nEU\n
Run Code Online (Sandbox Code Playgroud)\n\n

我们需要而不是常规的旧函数的原因Poly1是,我们无法收集组合普通函数时所需的不同证据\xe2\x80\x94,相反,我们需要多态函数值(Shapeless 提供为PolyN)。

\n\n

还值得注意的是,这并不是真正的“幺半群”。类型的幺半群实例提供了一种操作,该操作采用该类型的两个值并返回另一个值。这里mplus有两个操作,每个操作都有自己的隐含要求,并为我们提供了另一个操作,它具有两者的组合要求。

\n