我真的很想知道差异在哪里,更一般地说,找出不能使用HLists的规范用例(或者说,不会比常规列表产生任何好处).
(我知道TupleNScala 中有22个(我相信),而一个只需要一个HList,但这不是我感兴趣的那种概念差异.)
我在下面的文字中标出了几个问题.它实际上可能没有必要回答它们,它们更倾向于指出我不清楚的事情,并指导某些方向的讨论.
我最近在SO上看到了几个人们建议使用HLists的答案(例如,由Shapeless提供),包括对这个问题的删除答案.它引发了这一讨论,从而引发了这个问题.
在我看来,只有当您静态地知道元素的数量及其精确类型时,才会使用hlists.这个数字实际上并不重要,但你似乎不太可能需要生成一个包含不同但静态精确已知类型的元素的列表,但是你不能静态地知道它们的数量.问题1:你甚至可以写一个这样的例子,例如,在循环中吗?我的直觉是,拥有静态精确的hlist与静态未知数量的任意元素(相对于给定的类层次结构的任意)只是不兼容.
如果这是真的,即你静态地知道数字和类型 - 问题2:为什么不使用n元组?当然,你可以类型安全地映射和折叠一个HList(你也可以,但不是类型安全地,借助于一个元组productIterator),但由于元素的数量和类型是静态已知的,你可能只是访问元组元素直接执行操作.
另一方面,如果f您在hlist上映射的函数是如此通用以至于它接受所有元素 - 问题3:为什么不通过它使用它productIterator.map?好的,一个有趣的区别可能来自方法重载:如果我们有几个重载f的,拥有hlist提供的更强的类型信息(与productIterator相反)可以允许编译器选择更具体的f.但是,我不确定这在Scala中是否真的有用,因为方法和功能不一样.
基于相同的假设,即您需要静态地知道元素的数量和类型 - 问题4:可以在元素依赖于任何类型的用户交互的情况下使用hlists吗?例如,想象用循环内的元素填充hlist; 从某个地方(UI,配置文件,演员交互,网络)读取元素,直到某个条件成立.什么类型的hlist是什么?类似于接口规范getElements:HList [...]应该使用静态未知长度的列表,并允许系统中的组件A从组件B获得这样的任意元素列表.
我现在已经做了一些HList的实现.一个基于丹尼尔斯皮瓦克在斯卡拉之地的高级巫术讲话,另一个基于Apocalisp博客中的帖子.目标是有一个异类列表,其中主要类型不是异质的,而是更高类型.例如:
val requests = Request[String] :: Request[Int] :: HNil
Run Code Online (Sandbox Code Playgroud)
我可以在列表中执行映射来执行请求,并生成更高类型的异构列表.所以:
requests.map(execute)
Run Code Online (Sandbox Code Playgroud)
应该相等
String :: Int :: HNil
Run Code Online (Sandbox Code Playgroud)
可悲的是,我的所有尝试都产生了任何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 …Run Code Online (Sandbox Code Playgroud) 是否可以foldLeft在参数列表上执行a ,其中提供给fold的初始值是完全curried函数,运算符是apply,并且列表是要传递给函数的参数列表f?
例如,假设f定义为:
scala> val f = (i: Int, j: Int, k: Int, l: Int) => i+j+k+l
f: (Int, Int, Int, Int) => Int = <function4>
Run Code Online (Sandbox Code Playgroud)
我们当然可以直接使用它:
scala> f(1, 2, 3, 4)
res1: Int = 10
Run Code Online (Sandbox Code Playgroud)
或者咖喱并一次应用一个参数:
scala> f.curried
res2: Int => Int => Int => Int => Int = <function1>
scala> f.curried.apply(1).apply(2).apply(3).apply(4)
res3: Int = 10
Run Code Online (Sandbox Code Playgroud)
乍一看,这看起来像是一份工作foldLeft.
我第一次尝试描述这个apply使用顺序foldLeft如下:
scala> List(1, 2, 3, 4).foldLeft(f.curried)({ (g, x) => g.apply(x) …Run Code Online (Sandbox Code Playgroud) 我目前正在编写Slick代码来定位具有两个表> 22列的旧模式.如何使用新的HList代码?在Scala 2.10.3下,我在其他方面有2.0-M3正常工作.这是我目前使用的案例类/元组的语法.如何使用文档中提到的新HList?
case class Joiner(
id: Int,
name: Option[String],
contact: Option[String]
)
class Joiners(tag: Tag) extends Table[Joiner](tag, "joiner") {
def id = column[Int]("id", O.PrimaryKey, O.AutoInc, O.DBType("int(11)"))
def name = column[Option[String]]("name", O.DBType("varchar(255)"))
def contact = column[Option[String]]("contact", O.DBType("text"))
def * = (id, name.?, contact.?) <> (Joiner.tupled, Joiner.unapply)
}
val joiners = TableQuery[Joiners]
Run Code Online (Sandbox Code Playgroud)
我在示例中没有看到任何内容,只是在最新更新的文档中提及了一下.我是Scala和Slick的新手.
我在Scala中使用无形,我想编写一个函数allPairs,它将获取两个HLists并返回所有元素对的HList.例如:
import shapeless._
val list1 = 1 :: "one" :: HNil
val list2 = 2 :: "two" :: HNil
// Has value (1, 2) :: (1, "two") :: ("one", 2) :: ("one", "two") :: HNil
val list3 = allPairs(list1, list2)
Run Code Online (Sandbox Code Playgroud)
知道怎么做吗?
另外,我想强调一下我正在寻找一个函数,而不是一个内联的代码块.
是否有可能为无形'创建一个HList看起来如下的提取器.
val a ~ _ ~ b = 4 :: "so" :: 4.5 :: HNil
=> a == 4 && b == 4.5
Run Code Online (Sandbox Code Playgroud)
::为~,这应该不是问题.HNil.有没有可能出现的问题?经过多少汗水和泪水,我设法到达了以下代码的工作点:
for(
x1 :: _ :: x2 :: HNil <- (expInt ~ "+" ~ expInt).llE
) yield (x1 + x2)
Run Code Online (Sandbox Code Playgroud)
expInt解析Int一些monad E.类型(expInt ~ "+" ~ expInt).llE是E[Int :: String :: Int :: HNil].
我希望左边的模式在<-某种程度上类似于右边的组合子解析器的构造.
我想创建相当于:
def toTupleN[A1, ..., AN, L <: HList](l: L): TupleN[A1, ..., AN]
Run Code Online (Sandbox Code Playgroud)
代码使用toTupleN只有在只有一个N值组合时才能编译l,因为可以从中创建元组.其他任何东西都应该生成编译时错误.应考虑可用的隐式转换.请注意,对其中l的值的大小或顺序没有限制.
例:
val l = 23 :: (1, "wibble") :: (2, "wobble") :: "foo" :: HNil
// l: shapeless.::[Int,shapeless.::[(Int, String),shapeless.::[(Int, String),shapeless.::[String,shapeless.HNil]]]] = 23 :: (1,wibble) :: (2,wobble) :: foo :: HNil
val t2: (String, Int) = toTuple2(l)
// t2: (String, Int) = (foo,23)
val nope: (String, String) = toTuple2(l)
// Compiler error because no combination of l's values can create …Run Code Online (Sandbox Code Playgroud) 我目前正在实现一个库来序列化和反序列化XML-RPC消息.它几乎已经完成,但现在我正在尝试使用Shapeless删除当前asProduct方法的样板.我目前的代码:
trait Serializer[T] {
def serialize(value: T): NodeSeq
}
trait Deserializer[T] {
type Deserialized[T] = Validation[AnyErrors, T]
type AnyErrors = NonEmptyList[AnyError]
def deserialize(from: NodeSeq): Deserialized[T]
}
trait Datatype[T] extends Serializer[T] with Deserializer[T]
// Example of asProduct, there are 20 more methods like this, from arity 1 to 22
def asProduct2[S, T1: Datatype, T2: Datatype](apply: (T1, T2) => S)(unapply: S => Product2[T1, T2]) = new Datatype[S] {
override def serialize(value: S): NodeSeq = {
val params = …Run Code Online (Sandbox Code Playgroud) Slick的支持HList通常是一件好事.不幸的是,它带有自己的实现,几乎不提供任何有用的操作.因此,我想用无形 HList代替.这应该是" 微不足道的 ",但我不知道如何做到这一点.在网上搜索我发现没有证据表明某人设法完成了这项任务.
我认为这足以实现ProvenShape(如广告在这里),但因为我不明白的概念,油滑的 (Proven)Shape S,我没实现这一点.
我基本上是想把它煮沸
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( tag, "users" )
{
def id = column[Long]( "id", O.PrimaryKey, O.AutoInc )
def email = column[String]( "email" )
override def * = ( id, email ) <>[TableElementType, ( Long, String )](
_.productElements,
hlist => Some( hlist.tupled )
)
}
Run Code Online (Sandbox Code Playgroud)
向下
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( …Run Code Online (Sandbox Code Playgroud) 我想我需要一个受限制的HList,它的所有元素都是某种类型的子类型.LUBConstraint似乎是我想要的,事实上它确实限制了这样一个HList 的构造 - 但是我看不出如何再次获取证据,所以我可以映射(实际上,遍历,因为它需要是monadic)在HList上并调用每个元素上的方法(存在于LUB类型中).
另外,我希望从遍历操作得到的HList的类型与输入HList的类型完全相同.
用例是一种功能性的"监听器列表" - HList的所有元素都是"监听器",必须通知"事件",接受或拒绝它们,并返回更新的"内部状态"的新版本.如果这就是我所需要的,那么我可以使用普通的不可变Scala集合.但我也希望直接键入单个元素而不使用asInstanceOf- 因此尝试使用HList的动机.