Scala 使用shapeless从case类中提取数据、修改数据并重新创建case类

Scala 使用shapeless从case类中提取数据、修改数据并重新创建case类,scala,shapeless,Scala,Shapeless,我有一个带有一些案例类的程序。其中一个可能是Person,它依赖于其他一些类,包括一个称为StemedString的类,这在这里很重要: case class Person(name: String, skills: List[Skill], hobbbies: List[StemmedString] case class Skill(score: Int, title: StemmedString) case class StemmedString(original: String, stem

我有一个带有一些案例类的程序。其中一个可能是Person,它依赖于其他一些类,包括一个称为StemedString的类,这在这里很重要:

case class Person(name: String, skills: List[Skill], hobbbies: List[StemmedString]
case class Skill(score: Int, title: StemmedString)
case class StemmedString(original: String, stemmed: String)
现在我想把这个人翻译成另一种语言。为此,我想从Person->List[String]开始。这是需要翻译的单个字符串的列表。然后我想从List[String]->Person返回

我希望能够定义应该翻译的所有类型的东西,而不需要事先知道Person的格式,这样就可以在多个case类上进行归纳,这些case类由可以翻译的相同类型组成

假设我们翻译的都是词干字符串

我可以使用LabelledGeneric和flatMap创建两个HList,一个是要转换的值,另一个是不转换的值:

trait LowPriorityUnTranslatable extends Poly1 {
  implicit def default[T] = at[T](_ :: HNil)
}

object unTranslatable extends LowPriorityUnTranslatable {
  implicit def caseStemmedString[K, T] = at[FieldType[K, StemmedString]](x => HNil)
  implicit def caseSkill[K, T] = at[FieldType[K, Skill](x => HNil)
}


trait LowPriorityTranslatable extends Poly1 {
  implicit def default[T] = at[T](HNil)
}

object Translatable extends LowPriorityTranslatable {
  implicit def caseStemmedString[K, T] = at[FieldType[K, StemmedString]](_ :: HNil)
  implicit def caseSkill[K, T] = at[FieldType[K, Skill](_ :: HNil)
}
这感觉有点冗长,但效果很好。我现在有两个HList,它们可以使用align轻松连接并返回到原始的case类:

val person = Person("...")
val gen = LabelledGeneric[Person] 
val personList = gen.to(person)
val toTranslate = personList flatMap isTranslatable
val notTranslated = personList flatMap unTranslatable    
gen.from((toTranslate ++ notTranslated) align personList)

这是非常酷的,现在我需要做的就是在中间添加一个翻译步骤。当然,从isTranslatable->List[String]开始很容易,但是我不太明白如何以一种可以再次返回的方式完成这项工作。我开始尝试学习Shapess,因为它似乎是适合这种情况的工具,但我不太明白如何充分利用它。在我的头脑中,如果我,那么我会很好,但可能有一种更简单的方法来使用shapeless来解决这个问题。任何见解都将不胜感激

如果您不介意使用可变数据结构(在本例中是一个
迭代器),您可以使用
所有内容
/
无处不在
以获得简单的解决方案

首先,我们使用
everythings
查询提取要翻译的字符串;在本例中,我们提取
stemedString
对象的原始值。使用
Append
函数连接单例列表

trait translateableLP扩展了Poly1{
隐式def default[T]=at[T](=>Nil:List[String])
}
对象可平移扩展了可平移LP{
隐式def casestomedstring=at[stemedstring](s=>List(s.original))
}
对象附加扩展Poly2{
隐式val caseString=at[List[String],List[String](u加码)
}
val strings=所有内容(可翻译)(追加)(个人)
现在我们翻译字符串:

def translate(s:String):String=???
val translatedStrings=strings.map(translate)
最后,我们可以使用
随处可见的
转换字符串映射
stemedString
对象:

对象更新扩展了Poly1{
def iterator=translatedStrings.iterator
隐式def casestomedstring=at[stemedstring](u.copy(original=iterator.next))
}
val translated=无处不在(更新)(个人)

当我有时间的时候,我会尝试提出一个更干净的解决方案,只使用不可变的数据结构。

Beauty!如果你有时间的话,我很想看到一个只有不可变数据结构的版本!