Change card through monocle

I wanted to try the lenses, and the Monocle library seemed (from my point of view noobish) good with all these fancy @Lenses templates. Unfortunately, I learned that for beginners there is not enough material for training (I know the basics of FP in Scala vanilla, without Scalaz). The official textbook lacks simple examples (and / or their results), as well as a mixture in the rather complex Scalaz library. One could assume that such a trivial task as access to the map would be covered on the first page.

I have the following snippet:

  @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) 

I saw at and index , but no simple examples (just some weird [magic for me] answered applyOptional that required a template). I want to update the map - houses in Town . I tried something like that:

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

Which is syntactically incorrect, but I find it obvious what I wanted to do (change the presentsDelivered of House to the specified x, y coordinates). So my question is: how to change the index part to access the map ?

Any hints on a hint, a hint or a hollow allowance are welcome.

+5
source share
1 answer

You are literally one character (and possibly an import) from the solution:

 import monocle.function.all.index import monocle.std.map._ ( World.town ^|-> Town.houses ^|-? index((0, 0)) ^|-> House.presentsDelivered ).modify(_ + 1) 

Note that I replaced ^|-> immediately preceding the index with ^|-? . This is necessary because index((x, y)) fundamentally different from World.town and other macro- World.town lenses for members of the case class. They cannot indicate a value, and index can fail if there is no value in a given index on the map. In terms of types, Monocle index((x, y)) is Optional[Houses, House] , and World.town is Lens[World, Town] .

Options are weaker in sense than lenses, and as soon as you compose a lens with an option, you will have additional options, even if you create more lenses. So the lens:

 World.town ^|-> Town.houses 

But this is optional:

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

The monocle sequentially uses x ^|-> y to create various types of x (lenses, optional, bypasses, etc.) with lenses and x ^|-? y x ^|-? y to create different x with options. I personally think that operators are a little confused and prefer composeLens , composeOptional , etc., but the tastes are different, and if you want to remember the operators, you can at least be sure that they are used sequentially - you just need to know which one you need for this type.

Another potential problem with your code is that you cannot just write this:

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

This does not compile on its own because index requires an instance of a class of type index for the type into which it is indexed (in this case Map[(Int, Int), House] ). Monocle provides a generic instance for cards that will work, but you must import it:

 import monocle.std.map._ 

I’m afraid that I don’t have very good suggestions for training materials, but you can always ask questions here, and the Monocle Gitter channel is quite active.

+7
source

Source: https://habr.com/ru/post/1237773/


All Articles