Scala 用例类复制方法和命名参数的抽象

Scala 用例类复制方法和命名参数的抽象,scala,scalaz,shapeless,Scala,Scalaz,Shapeless,我使用的是scalaz state monad,我有以下问题: My state是一个案例类,包含不同类型的向量: case class Repository(instances: Vector[Instance], vpcs: Vector[Vpc], subnets: Vector[Subnet]….) 我想通过状态操作对存储库进行更改。例如,我想根据更新函数更新向量中的一些元素,如下所示: val applicative = Applicative[({type f[a] = Sta

我使用的是scalaz state monad,我有以下问题:
My state是一个案例类,包含不同类型的向量:

case class Repository(instances: Vector[Instance], vpcs: Vector[Vpc], subnets: Vector[Subnet]….)
我想通过状态操作对存储库进行更改。例如,我想根据更新函数更新向量中的一些元素,如下所示:

  val applicative = Applicative[({type f[a] = State[Repository, a]})#f]
  def createTags[T <: {def id : String}](memberSelector: Repository => Vector[T])(updateTags: T => T) =
    for {
      matchingResources <- State.gets((repo: Repository)=> memberSelector(repo).filter(t => resourcesIds.contains(t.id)))
      _ <- applicative.traverse(matchingResources)(matchingResource => State.modify((repo: Repository) => repo.copy(*** = memberSelector(repo).replaceFirst(matchingResource, updateTags(matchingResource)))))
    } yield ()
问题是,我无法抽象出调用Repository类的copy方法时要使用的命名参数(请参见上面代码中的***)。

我想Shapeless可能会帮助我做到这一点:我可以使用case类到HList同构来将存储库case类视为HList,然后使用HList操作来更新相关向量。但是我还没能让它工作。有可能通过不成形来实现吗?还有其他想法吗?

您应该能够使用镜头库,而不是直接使用case类复制功能。镜头是在A
B
中获取和设置一些
A
的机制。您已经以
memberSelector
的形式获取了get

e、 g使用monocale,它为创建镜头提供了很好的宏 (我实际上并没有对这个进行打字检查)


哇,谢谢,这很酷,而且很有效!我编译monocle代码时唯一需要做的一个小改动就是直接使用
State.modify(lens.modify…
而不是
State.modify((repo:Repository)=>lens.modify…
def replaceFirst(oldElem: A, newElem: A): Vector[A] = {
  val i = v.indexOf(oldElem)
  if (i == -1) v else v.updated(i, newElem)
}
object Repository {
  import monocle.Lens
  import monocle.macros.GenLens

  val _instances: Lens[Repository, Vector[Instance]] = GenLens[Repository](_.instances)
  val _vpcs: Lens[Repository, Vector[Vpc]] = GenLens[Repository](_.vpcs)
  ///...

  val applicative = Applicative[({type f[a] = State[Repository, a]})#f]
  def createTags[T <: {def id : String}](lens: Lens[Repository, Vector[T]])(updateTags: T => T) =
    for {
      matchingResources <- State.gets((repo: Repository)=> lens.get(repo).filter(t => resourcesIds.contains(t.id)))
      _ <- applicative.traverse(matchingResources)(matchingResource => State.modify((repo: Repository) => lens.modify(_.replaceFirst(matchingResource, updateTags(matchingResource)))))
    } yield ()
}
object Repository {
  import scalaz.Lens

  val _instances: Lens[Repository, Vector[Instance]] = Lens.lensu((r, i) => r.copy(instances = i), _.instances)
  ///...

  import scalaz.std.vector._
  import scalaz.syntax.traverse._
  def createTags[T <: {def id : String}](lens: Lens[Repository, Vector[T]])(updateTags: T => T) =
    for {
      matchingResources <- lens.map(_.filter(t => resourcesIds.contains(t.id)))
      _ <- matchingResources.traverseS_(matchingResource => lens.mods_(_.replaceFirst(matchingResource, updateTags(matchingResource))))
    } yield ()
}