Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Jun 28 14:38

    julien-truffaut on gh-pages

    Deploy website Deploy website … (compare)

  • Jun 28 14:33
    julien-truffaut closed #1285
  • Jun 28 14:33

    julien-truffaut on master

    Implemented generic `Index` for… (compare)

  • Jun 28 14:24
    julien-truffaut commented #1285
  • Jun 28 14:24
    julien-truffaut synchronize #1285
  • Jun 27 21:38

    julien-truffaut on gh-pages

    Deploy website Deploy website … (compare)

  • Jun 27 21:33

    xuwei-k on master

    Update refined, refined-scalach… (compare)

  • Jun 27 21:33
    xuwei-k closed #1288
  • Jun 27 21:02
    scala-steward-bot synchronize #1288
  • Jun 27 19:55
    scala-steward-bot synchronize #1288
  • Jun 27 19:08
    scala-steward-bot synchronize #1288
  • Jun 27 18:03
    scala-steward-bot synchronize #1288
  • Jun 27 17:20
    scala-steward-bot synchronize #1288
  • Jun 27 16:05
    scala-steward-bot synchronize #1288
  • Jun 27 15:02
    scala-steward-bot synchronize #1288
  • Jun 27 14:15
    scala-steward-bot synchronize #1288
  • Jun 27 13:38
    scala-steward-bot synchronize #1288
  • Jun 27 11:55
    scala-steward-bot synchronize #1288
  • Jun 27 11:04
    scala-steward-bot synchronize #1288
  • Jun 27 09:58
    scala-steward-bot review_requested #1288
Julien Truffaut
@julien-truffaut
that's why, it is only in the 3.0.0 milestone
nafg
@nafg
Tested on scastie, @Lenses works on 2.13.6
So idk why it stops working when I set my project to 2.13.6 rather than 2.13.5, at least in one particular file
Julien Truffaut
@julien-truffaut
any objection to make 3.0.0-M6, the first RC? Originally, I wanted to .field (optics-dev/Monocle#1125) but it can be added later
Carlos Quiroz
@cquiroz
👍
Tanay Taneja
@TanayTaneja_twitter

I am trying to create a lens, which accesses different fields in a case class, eg: GenLens[Person](_.details.age) , GenLens[Person](_.details.address) , GenLens[Person](_.details.name)

Is there a way I can do this by generalizing the changing field? Something like

val attribute = "name"
GenLens[Person](_.details.$attribute)
Julien Truffaut
@julien-truffaut
You can generate a Lens[Person, Details] and then compose it with GenLens[Details](_.age) or GenLens[Details](_.address)
not shorter though
Tanay Taneja
@TanayTaneja_twitter
I see :/
@julien-truffaut The above lens is part of a few more changes, I was wondering if I could pack it all inside a function, because the only difference there is in that genlens piece, do you have any suggestions on what could be a better way to do it?
Julien Truffaut
@julien-truffaut
not really, either you break it down in small pieces and you compose the optics or you generate the whole optic using macro like focus in Scala 3
fromscalatohaskell
@fromscalatohaskell_gitlab

I'm really stuck on something ... I'm trying to generate at runtime list of lenses to modify a data structure... here's simplified example:

  sealed trait TreeLike
  final case class Tree(id: String, leaves: List[Leaf]) extends TreeLike
  final case class Leaf(i: Int) extends TreeLike

  val tree = Tree(
    "t1", List(Leaf(1), Leaf(2), Leaf(3))
  )

  val treeLens = tree.focus()

  val lenses: List[AppliedLens[Tree, Leaf]] = ??? // list of lenses for leaves where i%2 ==0

how would I go about this? Where I essentially need to fold over runtime values to make lenses
btw kickass library

fromscalatohaskell
@fromscalatohaskell_gitlab
this seems to work, is it "correct" ?
  sealed trait TreeLike
  final case class Tree(id: String, leaves: List[Leaf]) extends TreeLike
  final case class Leaf(num: Int) extends TreeLike

  val tree = Tree(
    "t1", List(Leaf(1), Leaf(2), Leaf(3), Leaf(4))
  )

  val lenses: List[Traversal[Tree, Leaf]] =
    tree.leaves.map {
      x =>
        if (x.num % 2 == 0) {
          val ff = Focus[Tree](_.leaves)
            .andThen(Traversal.fromTraverse[List, Leaf])
            .andThen(
              Prism[Leaf, Leaf] { bi =>
                if (bi == x) Some(bi)
                else None
              }(identity)
            )
          Some(ff)
        } else None
    }.collect { case Some(x) => x }

  val res = lenses.foldLeft(tree) { case (t, lens) =>
    lens.modify(x => Leaf(x.num + 10))(t)
  }
nafg
@nafg
best way to know is to test it ;)
Julien Truffaut
@julien-truffaut
It seems that you could use a Traversal (optics that targets many values of the same type), Plated might also be an option, it deals with recursive data structures like your Tree https://github.com/optics-dev/Monocle/blob/master/example/src/test/scala/monocle/JsonExample.scala#L227-L259
fromscalatohaskell
@fromscalatohaskell_gitlab
I use traversal, it's more of a how to decide if we want lens for this field at runtime
the above works but it's weird that inside Prism I check if it's equal to thing the outside map is introducing
the above code would increment Leaf(2) and Leaf(4) because they %2...
but I wonder if there's better way... <== optics noob
Julien Truffaut
@julien-truffaut
if you use the latest version of Monocle, you can use .filter instead of a custom Prism
fromscalatohaskell
@fromscalatohaskell_gitlab
thanks!!! thats a bit nicer
any other tips?
Julien Truffaut
@julien-truffaut
I am not sure why you start with tree.leaves.map {
fromscalatohaskell
@fromscalatohaskell_gitlab
I need to return list of setters for parts of subtree essentially
Julien Truffaut
@julien-truffaut
It seems you could do
Focus[Tree](_.leaves).filter(_.num % 2 == 0)
fromscalatohaskell
@fromscalatohaskell_gitlab
in my real app i have analyser that checks it against some outside rules and returns List(Rule, Setter)
Julien Truffaut
@julien-truffaut
k
fromscalatohaskell
@fromscalatohaskell_gitlab
im not saying there's not better way, that's why I'm asking experts :)
I essentially recrusively validate the rules and zoom into the structure to build up "which rule violated which part of the structure, and setter to change it"
Julien Truffaut
@julien-truffaut
Monocle 3.0.0-RC2 is released with a new organisation (dev.optics)
https://twitter.com/JulienTruffaut/status/1399663531772022785
fromscalatohaskell
@fromscalatohaskell_gitlab
fantastic
Igal Tabachnik
@hmemcpy

Good evening all!

I was wondering how can I improve upon this manual thing I'm doing now?
Suppose I have a case class Person(name: String, age: Int). I receive a PATCH request, containing optional fields that may have changed. What I'm currently doing is manually building a bunch of Person => Person functions, either copying over the new value or returning the given person unchanged, then applying all those "patch" functions one after the other to the initial person.

Surely there's a better way :slight_smile:

case class PatchPersonRequest(name: Option[String], age: Option[Int])

val request = PatchPersonRequest(...)

val patchName: Person => Person = request.name.fold[Person => Person](identity)(n => p => p.copy(name = n))
val patchAge: Person => Person = request.age.fold[Person => Person](identity)(a => p => p.copy(age = a))
...

val updatedPerson = Patch.merge(
    person,
    patchName,
    patchAge
    ...
)

I'm using monocle to update deeply nested properties of person, but even then this is manual and repetitive... and boilerplatey :(

Patch.merge does a foldLeft over the Seq[A => A], applying it to the initial A...
Julien Truffaut
@julien-truffaut
you can improve the setting part in monocle 3 with n => p.focus(_.name).replace(n)
not shorter though
instead of doing fold maybe you could use foldMapM or other variants of foldMap
it is mostly to get rid of identity
Igal Tabachnik
@hmemcpy
Thanks! I was told that Chimney handles this exact scenario! https://scalalandio.github.io/chimney/patchers/options-handling.html
Julien Truffaut
@julien-truffaut
Nice
Igal Tabachnik
@hmemcpy
But I wonder if this could also be a good fit for an optics library.
Shah Saraei
@ShahOdin

I have a product type with optional types such as

case class Foo(bar1: Option[Bar1], bar2: Option[Bar2], bar3: Option[Bar3])

I will have a list of optional bar[i]s and I want to optionally modify my Foo instance with them.

as it stands I have to repeat _.focus.replace for each param. is there a way of abstracting it out? I tried doing that with something like:

def updateWith[T](f: Foo => Option[T]): ???

but I get:

Illegal field reference f; please use _.field1.field2... instead

is there a way of marking updateWith somehow to make this go away?

Julien Truffaut
@julien-truffaut
in Scala 3, you can do _.focus(_.bar1.some.xxx)
in Scala 2, you can do _.focus(_.bar1).some.andThen(Focus[Bar1](_.xxx))
Shah Saraei
@ShahOdin

Thanks Julien. I think you misunderstood my issue: I don't care about the nested types in BarXtypes here. I have maybeValues which I would like to update my model with, if they were Some() initially I wanted to do something like:

List(
  maybeBar1.map(updateWith),
  maybeBar2.map(updateWith)
).reduceLeft(..)

with the updateWith being responsible for the fold needed but then I faced the problem I described.

but I just realised I would be equally happy with something like:

foo
  .focus(_.bar1).replaceIfSome(maybeBar1)
  .focus(_.bar2).replaceIfSome(maybeBar2)

with the function looking something like:

  implicit class AppliedLensOps[A, C](lens: AppliedLens[A, Option[C]]) {
    def replaceIfSome(maybe: Option[C]): A = maybe.fold(
      lens.value
    )( w =>
      lens.replace(w.some)
    )
  }

is there a more generic way of doing this? :thinking

Julien Truffaut
@julien-truffaut
ah then, you can do
foo
  .focus(_.bar1).some.replace(maybeBar1)
  .focus(_.bar2).some.replace(maybeBar2)
Shah Saraei
@ShahOdin

tried above with Scala 2, I get:

found : Option[Bar1]
required: Bar1
.focus(.bar1).some.replace(maybeBar1)

Julien Truffaut
@julien-truffaut
maybeBar1 needs to be a Bar1
or do you want to set it to None if it is a Some?
Shah Saraei
@ShahOdin
see replaceIfSome impl above. I want to leave Foo alone if maybeBar is None, but replace its bar1 value if it's Some(_)
Julien Truffaut
@julien-truffaut
ah ok, you're right. I thought the if None / if Some logic was based on the field of Foo, but it is in fact based on maybeBar1
I should read more carefully next time