我知道使用 Shapeless 我可以做这样的事情:
import shapeless._, syntax.singleton._, record._
case class Foo(x: Int, y: String)
case class RichFoo(x: Int, y: String, z: Double)
def makeRich(foo: Foo): RichFoo = {
val x = ('z ->> 0.9)
val repr = LabelledGeneric[Foo].to(foo) + x
LabelledGeneric[RichFoo].from(repr)
}
val a = Foo(1, "hello")
val b = makeRich(a)
Run Code Online (Sandbox Code Playgroud)
现在我想写一个通用的方法来做到这一点:
trait Morph[A, B, AR, BR] {
def apply(a: A)(f: AR => BR): B
}
object Morph {
implicit def genericMorph[A, B, AR, BR](implicit genA: LabelledGeneric.Aux[A, AR], genB: LabelledGeneric.Aux[B, BR]): …Run Code Online (Sandbox Code Playgroud) 据我了解,依赖类型允许您不指定输出类型:
例如,如果您有一个类型类:
trait Last[In] {
type Out
}
Run Code Online (Sandbox Code Playgroud)
那么你可以在不指定输出类型的情况下召唤一个实例:
implicitly(Last[String :: Int :: HNil]) // output type calculated as Int
Run Code Online (Sandbox Code Playgroud)
Aux 模式允许您再次指定输出类型:
implicitly(Last.Aux[String :: Int :: HNil, Int])
Run Code Online (Sandbox Code Playgroud)
您需要在隐式参数列表中使用它,以便对输出类型做一些有用的事情(解决 Scala 对依赖类型的限制)。
但是如果你总是需要指定(或分配一个类型参数)输出类型,为什么首先要使用依赖类型(然后是 Aux)呢?
我尝试Last从 Shapeless 的 src复制类型类,替换type Out为特征中的附加类型参数并删除 Aux。它仍然有效。
当我真正需要它们时是什么情况?
我想定义一个函数,它接受一个 ,HList其元素是这样的,对于每个元素t,都有一个类型T使得t: Either[String, T]. 我们将调用的函数validate应具有以下行为:
Right,则返回Right右投影映射参数的结果。Left[List[String]],其中列表包含Left参数中每个的左投影。例子:
validate (Right (42) :: Right (3.14) :: Right (false) :: HNil)
>> Right (42 :: 3.14 :: false :: HNil)
Run Code Online (Sandbox Code Playgroud)
validate (Right (42) :: Left ("qwerty") :: Left ("uiop") :: HNil)
>> Left (List ("qwerty", "uiop"))
Run Code Online (Sandbox Code Playgroud)
一个示例用例:
case class Result (foo: Foo, bar: Bar, baz: Baz, qux: Qux)
def getFoo: Either[String, Foo] = …Run Code Online (Sandbox Code Playgroud) def unreturn(lx: Sized[List[Int], Nat._1]): Int = lx head
Run Code Online (Sandbox Code Playgroud)
如何使用shapeless获取一个元素列表的头部?这不编译:
No implicit view available from List[Int] =>
scala.collection.GenTraversableLike[v.A,List[Int]].
not enough arguments for method sizedOps:
(implicit evidence$2: List[Int] =>
scala.collection.GenTraversableLike[v.A,List[Int]])shapeless.
SizedOps[v.A,List[Int],shapeless.Nat._1]. Unspecified value parameter evidence$2.
Run Code Online (Sandbox Code Playgroud) 是否可以将HList作为函数参数传递?
这是我到目前为止:
import shapeless._
import poly._
object id extends (Id ~> Id) {
def apply[T](f: shapeless.Id[T]): shapeless.Id[T] = f
}
object ListHandler {
def mapOverHlist[ListType <: HList](list: ListType) = list.map(id)
}
val x = "foo" :: "bar" :: 0xb33f :: HNil
ListHandler.mapOverHlist(x)
Run Code Online (Sandbox Code Playgroud)
导致此错误:
could not find implicit value for parameter mapper:
shapeless.ops.hlist.Mapper[ShapelessSpec.this.id.type,ListType]
Run Code Online (Sandbox Code Playgroud) 为了这篇文章的目的,代码片段被轻视,抽样.
case class Person(firstName:String,lstName:String)
Run Code Online (Sandbox Code Playgroud)
此人类已在代码库中的所有位置使用.现在,后来的需求发生了变化,并决定phoneNumber在人案例类中添加
例如
case class Person(firstName:String,lstName:String,phoneNumber:String)
Run Code Online (Sandbox Code Playgroud)
再次,帖子中的例子极为简化.实际上,有更多有趣的事情正在发生.请注意,这phoneNumber不是Option必填字段.通常,人们会更新所有使用Person类的代码,以满足新领域的需求lastName.当你有100个引用它时,这是相当繁琐的.
HList从get get vs case class 创建更灵活的无形帮助?
我需要一个异构的,类型安全的容器来存储不相关的类型A,B,C.
这是一种类型级规范:
trait Container {
putA(a: A)
putB(b: B)
putC(c: C)
put(o: Any) = { o match {
case a: A => putA(a)
case b: B => putB(b)
case c: C => putC(c)
}
getAllAs : Seq[A]
getAllBs : Seq[B]
getAllCs : Seq[C]
}
Run Code Online (Sandbox Code Playgroud)
哪种类型是支持此容器的最佳套件?
是否值得为类型A,B,C创建容器[T]类型类?
THKS.
看看parboiled2部分,Rule Combinators and Modifiers:

我不明白的a,b和再a ~ b图.
到目前为止,我发现文档很简单.但我在这里有点失落.
你能解释一下这个街区吗?
我想将类的更新实例合并到基本实例中,如果基本实例中的该字段为"空",则选择基础实例上的更新实例的字段.以下示例合并base并update:
case class Foo(a: Option[Int], b: List[Int], c: Option[Int])
val base = Foo(None, Nil, Some(0))
val update = Foo(Some(3), List(4), None)
merge(base,update) == Foo(Some(3), List(4), Some(0))
Run Code Online (Sandbox Code Playgroud)
我尝试过这样的事情:
val g = Generic[Foo]
val aHList = g.to(base)
val bHList = g.to(update)
aHList
.zipWithIndex
.map({
case (l: List, i: Int) => l ++ bHList(i)
case (o: Option, i: Int) => if (!bHList(i).nonEmpty) {
updateHList(i)
} else {
o
}
case (_, i: Int) => updateHList(i)
})
Run Code Online (Sandbox Code Playgroud)
但事实证明,泛型.to方法不输出 …
试图映射自定义多态类的HList我得到了可怕的"无法找到参数映射器的隐式值"错误.代码示例:
import shapeless._
trait SubTrait
case class A() extends SubTrait
case class B() extends SubTrait
case class C[T <: SubTrait](x: T)
object TheMapper extends Poly1 {
implicit def default[T <: SubTrait, L[T] <: C[T]] = at[L[T]](_.x)
}
val ab = C(A()) :: C(B()) :: HNil
println(ab.map(TheMapper))
Run Code Online (Sandbox Code Playgroud)
如果L [T]的边界是例如Iterable(参见这个非常相似的问题,解决方案和注释),这可以正常工作.我错过了什么?