Laz*_*535 10 scala lenses monocle-scala
给出以下代码:
case class Person(name :String)
case class Group(group :List[Person])
val personLens = GenLens[Person]
val groupLens = GenLens[Group]
Run Code Online (Sandbox Code Playgroud)
我如何从选择中"过滤掉"某些人,不是通过索引而是通过特定属性Person,例如:
val trav :Traversal[Group, Person] = (groupLens(_.group) composeTraversal filterWith((x :Person) => /*expression of type Boolean here */))
Run Code Online (Sandbox Code Playgroud)
我只找到了这个filterIndex函数,它只包含基于索引的列表中的元素,但这不是我想要的.
filterIndex 采用类型的函数: (Int => Boolean)
而且我要:
filterWith(由名称构成),取a (x => Boolean),其中x具有lists元素的类型,即Person在这个简短的例子中.
这似乎是如此实际和普遍,以至于我认为有人已经考虑过这一点而且我(我必须承认对这个问题的理解有限)不明白为什么不能这样做.
我是否遗漏了这个功能,它是否尚未实现,或者由于某种原因显然是不可能的(如果你有时间,请解释).
谢谢.
Tra*_*own 14
我会从天真的尝试开始写这样的东西.我在这里使用的是一个简单的列表版本,但如果你愿意,你可以获得更好的(Traverse或者其他).
import monocle.Traversal
import scalaz.Applicative, scalaz.std.list._, scalaz.syntax.traverse._
def filterWith[A](p: A => Boolean): Traversal[List[A], A] =
new Traversal[List[A], A] {
def modifyF[F[_]: Applicative](f: A => F[A])(s: List[A]): F[List[A]] =
s.filter(p).traverse(f)
}
Run Code Online (Sandbox Code Playgroud)
然后:
import monocle.macros.GenLens
case class Person(name: String)
case class Group(group: List[Person])
val personLens = GenLens[Person]
val groupLens = GenLens[Group]
val aNames = groupLens(_.group).composeTraversal(filterWith(_.name.startsWith("A")))
val group = Group(List(Person("Al"), Person("Alice"), Person("Bob")))
Run Code Online (Sandbox Code Playgroud)
最后:
scala> aNames.getAll(group)
res0: List[Person] = List(Person(Al), Person(Alice))
Run Code Online (Sandbox Code Playgroud)
有用!
它有效,除了......
scala> import monocle.law.discipline.TraversalTests
import monocle.law.discipline.TraversalTests
scala> TraversalTests(filterWith[String](_.startsWith("A"))).all.check
+ Traversal.get what you set: OK, passed 100 tests.
+ Traversal.headOption: OK, passed 100 tests.
! Traversal.modify id = id: Falsified after 2 passed tests.
> Labels of failing property:
Expected List(?) but got List()
> ARG_0: List(?)
! Traversal.modifyF Id = Id: Falsified after 2 passed tests.
> Labels of failing property:
Expected List(??) but got List()
> ARG_0: List(??)
+ Traversal.set idempotent: OK, passed 100 tests.
Run Code Online (Sandbox Code Playgroud)
五分之三不是很好.
让我们重新开始:
def filterWith2[A](p: A => Boolean): Traversal[List[A], A] =
new Traversal[List[A], A] {
def modifyF[F[_]: Applicative](f: A => F[A])(s: List[A]): F[List[A]] =
s.traverse {
case a if p(a) => f(a)
case a => Applicative[F].point(a)
}
}
val aNames2 = groupLens(_.group).composeTraversal(filterWith2(_.name.startsWith("A")))
Run Code Online (Sandbox Code Playgroud)
然后:
scala> aNames2.getAll(group)
res1: List[Person] = List(Person(Al), Person(Alice))
scala> TraversalTests(filterWith2[String](_.startsWith("A"))).all.check
+ Traversal.get what you set: OK, passed 100 tests.
+ Traversal.headOption: OK, passed 100 tests.
+ Traversal.modify id = id: OK, passed 100 tests.
+ Traversal.modifyF Id = Id: OK, passed 100 tests.
+ Traversal.set idempotent: OK, passed 100 tests.
Run Code Online (Sandbox Code Playgroud)
好的,更好!
在"真实"的法律对Traversal在Monocle杂志的未编码TraversalLaws(至少不是在此刻),而且我们还希望这样的事情持有:
对于任何
f: A => A和g: A => A,t.modify(f.compose(g))应该相等t.modify(f).compose(t.modify(g)).
我们来试试吧:
scala> val graduate: Person => Person = p => Person("Dr. " + p.name)
graduate: Person => Person = <function1>
scala> val kill: Person => Person = p => Person(p.name + ", deceased")
kill: Person => Person = <function1>
scala> aNames2.modify(kill.compose(graduate))(group)
res2: Group = Group(List(Person(Dr. Al, deceased), Person(Dr. Alice, deceased), Person(Bob)))
scala> aNames2.modify(kill).compose(aNames2.modify(graduate))(group)
res3: Group = Group(List(Person(Dr. Al), Person(Dr. Alice), Person(Bob)))
Run Code Online (Sandbox Code Playgroud)
所以我们再次失去运气.我们filterWith实际上可以合法的唯一方法是,如果我们保证永远不会使用它,modify那么可能会改变谓词的结果.
这就是为什么filterIndex合法 - 它的谓词作为一个modify无法触及的论点,所以你不能违反t.modify(f.compose(g)) === t.modify(f).compose(t.modify(g))法律.
你可以写一个非法的Traversal非法过滤的东西,并一直使用它,它很可能永远不会伤害你,没有人会认为你是一个可怕的人.如果你愿意,那就去吧.但是,你可能永远不会filterWith在一个像样的镜头库中看到它.
| 归档时间: |
|
| 查看次数: |
1177 次 |
| 最近记录: |