以下要点有我正在玩的想法的代码
package com.test1
import scala.language.implicitConversions
import shapeless._
import FromTraversable._
import Traversables._
import Nat._
import Tuples._
trait ToArity[P, N <: Nat]
object ToArity {
implicit def prod1[P <: Product1[_]] = new ToArity[P, _1] {}
implicit def prod2[P <: Product2[_, _]] = new ToArity[P, _2] {}
// ad nauseum...
}
trait SizedHListAux[A, N <: Nat, T <: HList]
object SizedHListAux {
implicit def base[A, H <: HList] = new SizedHListAux[A, _0, HNil] {}
implicit def induct[A, H <: HList, N <: Nat, P <: Nat](implicit r: PredAux[N,P], k: SizedHListAux[A, P, H]) = new SizedHListAux[A, N, A :: H] {}
}
trait SomeFun {
type Result
def apply(): Result
}
// I want to abstract over A, the contained type in the List
// over P the Product type which is the arg notably its arity
// This means we need to recover arity of the Product type and render it in value space
// and also means that we need to compute the type of the intermediate HList
object SomeFun {
def produce(m: SomeFun): m.Result = m()
implicit def fromF1[T, A, P <: Product, N <: Nat, H <: HList](f1: (P => T, List[A]))(implicit k: ToArity[P, N], toI: ToInt[N], l: SizedHListAux[A, N, H], toHL: FromTraversable[H], tp: TuplerAux[H, P]) =
new SomeFun {
type Result = (T, List[A])
def apply(): Result = {
val (f, as) = f1
val (ts, rest) = (as.take(toI()), as.drop(toI()))
f((toHL(ts).get).tupled) -> rest
}
}
// Debug Arity checker
def printArity[P <: Product, N <: Nat](p: P)(implicit k: ToArity[P, N], toI: ToInt[N]) = println("Arity: " + toI())
}
object Test {
val thedata = List("foo", "bar", "baz", "bob")
val tfn = (x: (String, String)) => println("%s and %s".format(x._1, x._2))
def foo = SomeFun.printArity("a" -> "b")
//def doit = SomeFun.produce((tfn, thedata)) // Adding this line does not compile
}
Run Code Online (Sandbox Code Playgroud)
这个想法是你使用函数的参数arity,在这种情况下是产品类型的arity,来驱动解析相关的List [A].有点像使用胶带从石墨上剥离石墨烯层,即功能的类型将事物从列表中拉出来.这只是一个使用单个包含类型的草图,但我想它可以推广.重要的方面是函数本身不知道List处理.
然而......当试图解决ToArity [P,N]隐含时,这个概念似乎失败了.如printArity()所示,其自身的ToArity是可解析的.
有人可以解释为什么在fromF1的背景下这是不可解决的吗?它是否无法解析所有依赖的implicits然后将错误注册到第一个,即无法找到N来满足ToArity,ToInt和SizedHListAux?
更新:我刚刚看到你的编辑,这意味着你已经解决了前几段中提到的问题,但我希望其余部分有用.
问题是您的SizedHListAux
实例未被推断:
scala> implicitly[SizedHListAux[String, _1, String :: HNil]]
<console>:25: error: could not find implicit value for parameter e...
Run Code Online (Sandbox Code Playgroud)
幸运的是,这是一个简单的修复:
object SizedHListAux {
implicit def base[A] = new SizedHListAux[A, _0, HNil] {}
implicit def induct[A, H <: HList, N <: Nat, P <: Nat](implicit
r: PredAux[N, P],
k: SizedHListAux[A, P, H]
) = new SizedHListAux[A, N, A :: H] {}
}
Run Code Online (Sandbox Code Playgroud)
我刚刚删除了R <: PredAux[N, P]
type参数并r
正确输入.我也删除未使用的类型参数H
上base
,即使它并没有造成问题,它只是没有做任何事情.
这几乎全部 - 现在所有fromF1
推断的实例:
scala> SomeFun.fromF1((tfn, thedata))
res0: SomeFun{type Result = (Unit, List[String])} = SomeFun$$anon$1@7eacbeb
Run Code Online (Sandbox Code Playgroud)
你仍然不会得到从类型视图(tfn, thedata)
来SomeFun
,虽然.请考虑以下简化示例:
scala> trait Foo
defined trait Foo
scala> trait Bar[A, B]
defined trait Bar
scala> implicit def toInt[F <: Foo, X](f: F)(implicit ev: Bar[F, X]) = 42
toInt: [F <: Foo, X](f: F)(implicit ev: Bar[F,X])Int
scala> implicit object fooBar extends Bar[Foo, String]
defined module fooBar
scala> toInt(new Foo {})
res0: Int = 42
scala> implicitly[Foo => Int]
<console>:12: error: No implicit view available from Foo => Int.
implicitly[Foo => Int]
Run Code Online (Sandbox Code Playgroud)
因此,即使我们有范围的隐式方法,将变换Foo
成一个Int
,这X
会导致编译器问题,当它试图找到一个视图Foo
来Int
.
在你的情况下,我会通过跳过SomeFun
业务并使用一个方法来获取(P => T, List[A])
并返回一个来避免这种限制(T, List[A])
.
我也会观察这两个ToArity
和SizedHListAux
似乎是不必要的,因为你可以收集用同样的证据TuplerAux
,LengthAux
和LUBConstraint
.例如:
import shapeless._
trait SomeFun {
type Result
def apply(): Result
}
implicit def fromF1[T, A, P <: Product, N <: Nat, H <: HList](
f1: (P => T, List[A])
)(implicit
tp: TuplerAux[H, P],
hl: LengthAux[H, N],
toHL: FromTraversable[H],
allA: LUBConstraint[H, A],
toI: ToInt[N]
) = new SomeFun {
type Result = (T, List[A])
def apply(): Result = {
val (f, as) = f1
val (ts, rest) = (as.take(toI()), as.drop(toI()))
f((toHL(ts).get).tupled) -> rest
}
}
Run Code Online (Sandbox Code Playgroud)
然后:
val tfn = (x: (String, String)) => println("%s and %s".format(x._1, x._2))
val thedata = List("foo", "bar", "baz", "bob")
val sf = fromF1((tfn, thedata))
Run Code Online (Sandbox Code Playgroud)
最后:
scala> sf()
foo and bar
res2: (Unit, List[String]) = ((),List(baz, bob))
Run Code Online (Sandbox Code Playgroud)
不需要烦人的prodN
样板.
归档时间: |
|
查看次数: |
278 次 |
最近记录: |