通过Monocle修改地图

时间:2015-12-09 16:36:56

标签: scala monocle-scala

我想尝试镜头,Monocle图书馆似乎(从我的犹豫不决的角度来看)对所有那些花哨的样板很少@Lenses。不幸的是我发现初学者几乎没有非学习材料(我知道香草Scala的基础知识,没有Scalaz)。官方教程缺少简单的示例(和/或其结果),并且在非常复杂的Scalaz库中混合使用。人们会认为,访问地图这样的微不足道的任务将覆盖在第一页上。

我有以下代码段:

  @Lenses case class House(presentsDelivered: Int)

  type Houses = Map[(Int, Int), House]

  @Lenses case class Town(houses: Houses)

  @Lenses case class Santa(x: Int, y: Int)

  @Lenses case class World(santa: Santa, town: Town)

我看到atindex,但没有简单的例子(只有一些奇怪的[魔法对我来说]回答applyOptional需要样板文件)。我想在houses更新地图 - Town。我正在尝试这种精神:

(World.town ^|-> Town.houses ^|-> index((x, y)) ^|-> House.presentsDelivered)
  .modify { _ + 1 }(world)

这在语法上是错误的,但我认为我想做的很明显(在指定的presentsDelivered坐标处修改House x, y)。我的问题是,如何修改index部分以访问地图

欢迎任何帮助,线索或noob友好的学习材料提示。

1 个答案:

答案 0 :(得分:9)

你实际上只有一个角色(也许是一个导入)远离解决方案:

import monocle.function.all.index
import monocle.std.map._

(
  World.town              ^|->
  Town.houses             ^|-?
  index((0, 0))           ^|->
  House.presentsDelivered
).modify(_ + 1)

请注意,我已使用^|->替换了索引前面的^|-?。这是必要的,因为index((x, y))World.town以及案例类成员的其他宏生成镜头根本不同。那些不能指向某个值,而如果地图中给定索引处没有值,index可能会失败。就Monocle类型而言,index((x, y))Optional[Houses, House],而World.townLens[World, Town]

选项在某种意义上比镜头更弱,一旦你用可选镜头组成镜头,即使你制作了更多镜头,你也会继续选择。所以以下是一个镜头:

World.town ^|-> Town.houses

但这是可选的:

World.town ^|-> Town.houses ^|-? index((0, 0)) ^|-> House.presentsDelivered

Monocle始终使用x ^|-> y使用镜头构建不同类型的x(镜头,可选项,遍历等),并使用x ^|-? y组合不同的x选配。我个人觉得操作员有点困惑,喜欢composeLenscomposeOptional等,但口味各不相同,如果你想记住操作员,你至少可以确信他们已经被使用了始终如一 - 您只需要知道给定类型需要哪一个。

您的代码的另一个潜在问题是您不能写这个:

import monocle.function.all.index

val houses: monocle.Optional[Houses, House] = index((0, 0))

这不会自行编译,因为index需要Index类型的实例作为其索引类型(在本例中为Map[(Int, Int), House] Monocle为可以使用的地图提供了一个通用实例,但你必须导入它:

import monocle.std.map._

我担心我没有对学习材料提出任何非常好的建议,但你总是可以在这里提出问题,Monocle Gitter channel相当活跃。