我想尝试镜头,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)
我看到了at
和index
,但没有简单的例子(只是一些奇怪[魔术对我来说]与回答applyOptional
这需要样板).我想更新地图 - houses
在Town
.我正在尝试这种精神:
(World.town ^|-> Town.houses ^|-> index((x, y)) ^|-> House.presentsDelivered) .modify { _ + 1 }(world)
这在语法上是错误的,但我认为这是明显的就是我想要做的(修改presentsDelivered
的House
在指定x, y
坐标).所以我的问题是,如何修改index
部件以访问地图?
欢迎任何帮助,线索或noob友好的学习材料提示.
你实际上只有一个角色(也许是一个导入)远离解决方案:
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.town
一个是Lens[World, Town]
.
选项在某种意义上比镜头更弱,一旦你用可选镜头组成镜头,即使你拍摄更多镜头,你也会继续选择.所以以下是一个镜头:
World.town ^|-> Town.houses
但这是可选的:
World.town ^|-> Town.houses ^|-? index((0, 0)) ^|-> House.presentsDelivered
Monocle一直用镜片x ^|-> y
组成不同类型的x
镜片(镜片,可选镜片,穿越镜等),并用可选镜片x ^|-? y
组成不同x
的镜片.我个人觉得运营商有点混乱,喜欢composeLens
,composeOptional
等,但口味也不尽相同,如果你想记住的运营商,你至少可以确信,他们已经习惯一致,你只需要知道你需要哪一个给定的类型.
您的代码的另一个潜在问题是您不能只写这个:
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频道相当活跃.