可以在 Scala HList 上执行 Map 吗
我现在已经完成了一些 HList 的实现。一篇基于 Daniel Spiewak 的 High Wizardry in the Land of Scala 演讲,另一篇基于 Apocalisp 博客中的一篇文章。目标是拥有一个异质列表,其中的主要类型不是异质的,而是高级类型的。例如:
val requests = Request[String] :: Request[Int] :: HNil
我可以在列表中进行映射来执行请求并生成更高类型的异构列表。所以:
requests.map(execute)
应该等于
String :: Int :: HNil
遗憾的是我所有的尝试都导致了 Any 的 HList 。以下是最近一次尝试的代码:
class Request[+Out](o:Out) {
type O = Out
def v:O = o
}
object HList {
trait Func[-Elem,Out] {
type Apply[E <: Elem] <: Out
def apply[N <: Elem](e:N):Apply[N]
}
sealed trait HList[Base] {
type Head <: Base
type Tail <: HList[Base]
type Map[Out,F <: Func[Base,Out]] <: HList[Out]
def head:Head
def tail:Tail
def ::[A <: Base](a:A):HList[Base]
def map[Out,F <: Func[Base,Out]](f:F):Map[Out,F]
}
case class HNil[Base]() extends HList[Base] {
type Head = Nothing
type Tail = Nothing
type Map[Out,F <: Func[Base,Out]] = HNil[Out]
def head = error("Head of an empty HList")
def tail = error("Head of an empty HList")
def ::[A <: Base](a:A) = HCons(a,this)
def map[Out,F <: Func[Base,Out]](f:F) = new HNil[Out]
}
case class HCons[Base,A <: Base,B <: HList[Base]](head: A, tail: B) extends HList[Base] {
type Head = A
type Tail = B
type Map[Out,F <: Func[Base,Out]] = HCons[Out,F#Apply[Head],Tail#Map[Out,F]]
def ::[C <: Base](c:C) = HCons(c,this)
def map[Out,F <: Func[Base,Out]](f:F) =
HCons(f(head),tail.map(f))
}
val :: = HCons
}
object Test extends Application {
import HList._
val HNil = new HNil[Request[_]]
val list = new Request[Int](1) :: new Request[String]("1") :: HNil
val (a :: b :: HNil) = list
val y:Request[String] = b
val results = list.map[Any,Unwrap.type](Unwrap)
val i:Int = results.head
}
import HList._
object Unwrap extends Func[Request[Any],Any] {
type Apply[I <: Request[Any]] = I#O
def apply[N <: Request[Any]](e:N) = null.asInstanceOf[Apply[N]]
}
另一次尝试基于 Apocalisp 版本,该版本使用 Fold 来创建新的 HList,并且再次生成了 Any 类型的 HList。任何提示将不胜感激。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
shapeless 中的
HList
实现足够丰富,可以包含HList< /code> 和
KList
功能。它提供了一个map
操作,该操作在其元素中应用更高排名的函数(可能具有特定于类型的情况),从而产生适当类型的HList
结果,请注意,尽管情况如此在上面的示例中,不要求 HList 元素共享一个公共的外部类型构造函数,只需映射的较高级别的函数具有所有涉及的类型的情况即可,
现在让我们将其映射到
HList
,在这种情况下,被映射函数的结果类型是恒定的:无论参数类型是什么,它都是一个 Int。因此,生成的 HList 具有所有相同类型的元素,这意味着它可以有效地转换为普通列表,
The
HList
implementation in shapeless is rich enough to subsume bothHList
andKList
functionality. It provides amap
operation which applies a higher-ranked function, possibly with type-specific cases, across it's elements yielding an appropriately typedHList
result,Note that although it's the case in the above example there's no requirement that the HList elements share a common outer type constructor, it just has to be the case that the higher-ranked function mapped with has cases for all of the types involved,
Now let's map this across an
HList
,In this case the result type of the function being mapped is constant: it's an Int no matter what the argument type is. Consequently the resulting HList has elements all of the same type, which means that it can usefully be converted to a vanilla list,
你需要的是一个带有类型构造函数
Request
的 Klist,以及一个自然转换execute: Request ~>; id
。所有这些都在 Apocalisp 精彩的类型级编程系列文章中进行了详细介绍,特别是:您可以从 Mark Harrah 的 up 存储库
在您的情况下,您需要类似
上面的
down
方法,其概念上与 <用于 nat 传输的 code>mapM ~> id
;你还有更通用的map
,它来自nat transfM ~>; N
和类型 M 的 Klist 生成类型 N 的 KList。what you need is a Klist with type constructor
Request
, and a natural transformationexecute: Request ~> Id
. All of this is detailed in the marvelous type-level programming series of posts at Apocalisp, in particular:you can checkout the code for the whole series from Mark Harrah's up repo
In your case, you'll need something like
the
down
method above is conceptually the same asmap
for a nat transfM ~> Id
; you also have more generalmap
which from a nat transfM ~> N
and a Klist of kind M yields a KList of kind N.请注意,最近(2016 年 10 月,OP 发布 5 年后)文章“使用 shapeless 的 HList 实现额外的类型安全(在 Akka Streams 中)”来自 Mikołaj Koziarkiewicz。
Note that you have an example of Map with HList in the recent (October 2016, 5 years after the OP) article "Using shapeless' HLists for extra type safety (in Akka Streams)" from Mikołaj Koziarkiewicz.