将无形的可扩展记录传递给函数(永无止境的故事? [英] Passing a shapeless extensible record to a function (never ending story?

查看:33
本文介绍了将无形的可扩展记录传递给函数(永无止境的故事?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我继续研究可扩展记录,如传递无形状函数的可扩展记录(续):所提供的解决方案适用于所有采用至少包括 foo1、foo2 和 foo3 的参数的函数;这是一个可以写的:

I continue to investigate extensible records as in Passing a Shapeless Extensible Record to a Function (continued): the provided solution works with functions that all takes a parameter that includes at least foo1, foo2, and foo3; that is one can write:

fun1(("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: HNil)
fun1(("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: ("foo4" ->> true) :: HNil)

等等

如果我们可以添加第二个函数 fun2:

And if we can add a second function fun2:

def fun2[L <: HList : HasMyFields](xs: L) = {
  val selectors = implicitly[HasMyFields[L]]
  import selectors._
  xs("foo1").length + xs("foo2") + xs("foo3")
}

到目前为止,一切都很好.

So far, so good.

现在,让我们假设我们有一组字段 foo1, foo2,... 和一组函数 fun1, fun2,它们以由 {foo1, foo2,...} 的任何子集组成的记录作为参数.例如,fun1 可以将包含 foo1 和 foo3 但不一定是 foo2 的记录作为参数,fun2 会期望至少包含 foo4 的记录,依此类推.

Now, let's assume we have a set of fields foo1, foo2,... And a set of functions fun1, fun2, which take as parameter a record composed with any subset of {foo1, foo2,...}. For example, fun1 could take as parameter a record that contains foo1 and foo3 but not necessarily foo2, fun2 would expects a record with at least foo4 and so on.

有没有办法避免声明尽可能多的类,如 HasMyFields,因为它们是可能的组合(如果我们有 n 个字段,则有 2**n 个组合!)?

Is there a way to avoid to declare as many class like HasMyFields as they are possible combinations (if we have n fields, there are 2**n combinations!)?

推荐答案

如果没有使用新式 Witness 语法的额外类型类,这会容易得多:

This is a lot easier without an additional type class with the new-ish Witness syntax:

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

// Uses "foo1" and "foo2" fields; note that we get the appropriate static types.
def fun1[L <: HList](l: L)(implicit
   foo1: Selector.Aux[L, Witness.`"foo1"`.T, String],
   foo2: Selector.Aux[L, Witness.`"foo2"`.T, Int]
): (String, Double) = (foo1(l), foo2(l))

然后如果我们有这个记录:

And then if we have this record:

val rec = ("foo1" ->> "hello") :: ("foo2" ->> 1) :: ("foo3" ->> 1.2) :: HNil

我们明白了:

scala> fun1(rec)
res0: (String, Double) = (hello,1.0)

新语法允许我们避免单独创建见证值,因此只需要您需要的 Selector 实例非常容易.

The new syntax allows us to avoid creating witness values separately, so it's pretty easy to just require the Selector instances you need.

这篇关于将无形的可扩展记录传递给函数(永无止境的故事?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆