scalamonocle-scala

Modify sequence at index using Monocle


I can modify Map using focus and index just fine. Is there a similar functionality in Monocle to update a sequence at given index?

import monocle.syntax.all._

case class C(member: Int)

val map = Map(0 -> C(0), 1 -> C(1))
case class MapContainer(seq: Map[Int, C])
val containedMap = MapContainer(map)
containedMap.focus(_.seq).index(0).replace(C(10)) // works fine

val seq = IndexedSeq(C(0), C(1), C(2))
case class Container(seq: IndexedSeq[C])
val containedSeq = Container(seq)

containedSeq.focus(_.seq).index(0).replace(C(10)) // does not compile

The error is Could not find an instance of Index[IndexedSeq[C],Int,A1].

Is such functionality available for Monocle? I was using Quicklens previously and it used at for both maps and sequences. Unfortunately Quicklens Scala 3 support is not very good at this point, therefore I am exploring alternatives.


Solution

  • From what I see .index relies on Index instance which should be available for the type that you want to apply index to.

    If you modify your code to this:

    val seq = IndexedSeq(C(0), C(1), C(2))
    case class Container(seq: List[C]) // List instead of IndexedSeq
    val containedSeq = Container(seq.toList)
    
    containedSeq.focus(_.seq).index(0).replace(C(10))
    

    it does compile.

    So the issue is lack of instance for IndexedSeq. Among the build-in instances for standard data types you can see:

      implicit def seqIndex[A, S[B] <: SeqOps[B, S, S[B]]]: Index[S[A], Int, A] // this should work
      implicit def listIndex[A]: Index[List[A], Int, A]
      implicit def lazyListIndex[A]: Index[LazyList[A], Int, A]
      implicit def listMapIndex[K, V]: Index[ListMap[K, V], K, V]
      implicit def mapIndex[K, V]: Index[Map[K, V], K, V]
      implicit def sortedMapIndex[K, V]: Index[SortedMap[K, V], K, V]
      implicit val stringIndex: Index[String, Int, Char]
      implicit def vectorIndex[A]: Index[Vector[A], Int, A]
    

    but from what I see seqIndex was added 2 months ago and not released yet (3.1.0 was released a year ago).

    So your best bet is to use some specific data structure or implement this implicit yourself.