是否可以一般性地替换案例类中的参数?更具体地说,我想要一个替代函数,它接收一个"查找"案例类和一个"替换"案例类(如语法规则的左侧和右侧)以及一个目标案例类,该函数将返回一个将case case类的参数替换为replace case类的新case类?该函数还可以简单地将case类(Product?)和一个函数应用于case类的所有参数/产品.
显然,给定一个特定的case类,我可以使用unapply和apply - 但是一般来说(给定任何case类)编写这种函数的最好/最简单/等方法是什么?
我想知道是否有一个很好的解决方案,使用Scala 2.10反射功能或无形的Iso.hlist.
例如,我真正希望能够做的是,给出如下的类......
class Op[T]
case class From(x:Op[Int]) extends Op[Int]
case class To(x:Op[Int]) extends Op[Int]
case class Target(a:Op[Int], b:Op[Int]) extends ...
// and lots of other similar case classes
Run Code Online (Sandbox Code Playgroud)
...有一个函数可以接受任意的case类并返回它的副本,其中任何类型的元素都替换为To类型的实例.
编写算法HList,我需要一个zipWithIndex函数.它现在不在无形图书馆,所以我决定实施它.
很明显它可能被实现为
hlist.zip(indexes)
Run Code Online (Sandbox Code Playgroud)
这里indexes是HList索引(0到n),这可能可以得到这样的:
val indexes = Nat._0 until hlist.length
Run Code Online (Sandbox Code Playgroud)
这里的问题是Nat没有until方法.我还没有发现任何Witness对HList与使用索引HList.map.
什么是我可以用它来获取方法HList的Nat以S开始Nat._0至hlist.length?
我有这个代码,我想改进:
sealed abstract class A
case class B() extends A
case class C() extends A
case class D() extends A
case class Foo[+T <: A](a: T)
/** Puts instances that match Foo(B()) in the first list and everything else,
* i.e. Foo(C()) and Foo(D()), in the second list. */
def partition(foos: List[Foo[_ <: A]]): (List[Foo[B]], List[Foo[_ <: A]]) = {
// ...
}
Run Code Online (Sandbox Code Playgroud)
我想在以下方面对此进行改进:
partition返回类型,以便它表明Foo[B]第二个列表中没有吗?Foo类型参数T(即更改Foo为case class Foo(a: A) …Shapeless有一个简洁的类型派生机制,允许您定义类型类并获得任何类型类的自动派生.
要将派生机制用作类型类的用户,可以使用以下语法
import MyTypeClass.auto._
Run Code Online (Sandbox Code Playgroud)
据我所知,它相当于
import MyTypeClass.auto.derive
Run Code Online (Sandbox Code Playgroud)
当您尝试在同一范围内尝试使用多个类型类时会出现问题.看起来Scala编译器只考虑了derive的最后一个定义,即使它的隐式参数有两个版本的函数"重载".
我可以通过几种方法来解决这个问题.我不会在这里列出它们,而是将它们标记为答案,您可以投票确认理智并提出任何更好的解决方案.
scala typeclass type-level-computation shapeless scala-macros
从数据容器(例如案例类)中提取类型的最佳方法是什么.
例如,如果我有type Tagged[U] = { type Tag = U}标记类型trait PID,标记为Int type ProductId = Int with Tagged[PID]或scalaz样式,type ProductId = Int @@ PID并说明产品type Name = String @@ PName等中的其他字段和包含产品属性的数据容器;
case class Product(pid: ProductId, name: Name, weight: Weight)
Run Code Online (Sandbox Code Playgroud)
如何在A => B不诉诸反射的情况下编写通用的提取器样式方法?
原因是我想在运行时从Product容器中动态提取字段.即,用户传递他们想要提取的产品的属性.
即如果我想动态获取ProductId,我可以编写一个接受类型并返回值的方法,例如
trait Extractor[A] {
def extract[B](i: A): B = //get type B from the Product class
}
Run Code Online (Sandbox Code Playgroud)
或者我是在复杂的事情.
我可以编写简单的提取器类,它采用A => B函数并为每种类型定义它;
trait Getter[A, B] {
def extract(i: A): B …Run Code Online (Sandbox Code Playgroud) 假设我有一个HList类型A::B::C::HNil和一个函数(A, B, C) => D
val hlist: A::B::C::HNil = ???
def foo(a: A, b: B, c: C): D = ???
Run Code Online (Sandbox Code Playgroud)
现在我需要一个功能可按A::B::C::HNil => D,它使用foo返回D.
def bar(hslist: A::B::C::HNil): D = ???
Run Code Online (Sandbox Code Playgroud)
你会如何实施bar?
类型级别foldRight工作正常(getLabelWithValues),后续类型级别map(getValues)也可以正常工作.如果我在一个方法(getValuesFull)中组合两者,它就不再起作用了.丢失的是什么?
完整的源代码(sbt准备好~run使用隐式调试输出)在这里:https://github.com/mpollmeier/shapeless-playground/tree/8170a5b
case class Label[A](name: String)
case class LabelWithValue[A](label: Label[A], value: A)
val label1 = Label[Int]("a")
val labels = label1 :: HNil
object combineLabelWithValue extends Poly2 {
implicit def atLabel[A, B <: HList] = at[Label[A], (B, Map[String, Any])] {
case (label, (acc, values)) ?
(LabelWithValue(label, values(label.name).asInstanceOf[A]) :: acc, values)
}
}
object GetLabelValue extends (LabelWithValue ~> Id) {
def apply[B](labelWithValue: LabelWithValue[B]) = labelWithValue.value
}
val labelsWithValues: LabelWithValue[Int] :: HNil = getLabelWithValues(labels) …Run Code Online (Sandbox Code Playgroud) 在下面的代码中,我尝试使用shapeless派生类型类实例.但是,在更复杂的案例类(转换为更复杂的HList)的情况下,编译器给我一个"分歧的隐式扩展",即使它似乎没有两次解析相同类型的隐式类型.也许我错过了编译器的其他一些规则?
(小提琴:https://scalafiddle.io/sf/WEpnAXN/0)
import shapeless._
trait TC[T]
sealed trait Trait1
case class SimpleClass(a: String) extends Trait1
sealed trait Trait2
case class ComplexClass(a: String, b: String) extends Trait2
object Serialization extends App {
//Instances for HList
implicit val hnilInstance: TC[HNil] = ???
implicit def hconsInstance[H, T <: HList] (implicit t: TC[T]): TC[H :: T] = ???
//Instances for CoProduct
implicit val cnilInstance: TC[CNil] = ???
implicit def cconsInstance[H, T <: Coproduct] (implicit h: TC[H], t: TC[T]): TC[H :+: …Run Code Online (Sandbox Code Playgroud) 我使用无形库编写了这个简单的代码
import shapeless.LabelledGeneric
case class Icecream(name: String, numberOfCherries: Int, inCone: Boolean)
object ShapelessRecordEx2 extends App {
val gen = LabelledGeneric[Icecream]
val hlist = gen.to(Icecream("vanilla", 2, false))
hlist match {
case h :: _ => println(h)
}
}
Run Code Online (Sandbox Code Playgroud)
但是甚至没有编译
Error:(12, 14) constructor cannot be instantiated to expected type;
found : scala.collection.immutable.::[B]
required: shapeless.::[String with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("name")],String],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("numberOfCherries")],Int],shapeless.::[Boolean with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("inCone")],Boolean],shapeless.HNil]]]
case h :: _ => println(h)
Run Code Online (Sandbox Code Playgroud)
如果我正在使用普通列表,那么这段代码就可以了.
Scala 2.12.6,无形2.3.3
我有很多很深的大型模型(案例类)。我使用shapeless来帮助使用/操纵这些模型,还使用诸如circe之类的库,这些库大量使用了shapeless。
这导致我的编译时间在phase typerscalac 期间大大增加。
基于一点谷歌搜索,看起来无形是罪魁祸首,但是我似乎找不到任何有关如何改进它的具体技巧。
有人建议,因为我要为同一模型多次解析HList隐式(由于有多个库),所以我应该“缓存”它们-但是我不确定如何确切地找出要缓存的内容。
给出类似的东西:
case class MyModel(value: String) extends AnyVal
case class MyOtherModel(value: Int) extends AnyVal
case class MyRootModel(myModel: MyModel, myOtherModel: MyOtherModel)
Run Code Online (Sandbox Code Playgroud)
我应该为MyModel/ MyOtherModel和缓存什么MyRootModel?
scala ×10
shapeless ×10
implicit ×2
typeclass ×2
case-class ×1
generics ×1
hlist ×1
lenses ×1
reflection ×1
scala-macros ×1
scalaz ×1
types ×1