Skip to content

Instantly share code, notes, and snippets.

@neutropolis
Created September 28, 2017 15:00
Show Gist options
  • Save neutropolis/0d8e74285d7b4ec2349190ebe3056985 to your computer and use it in GitHub Desktop.
Save neutropolis/0d8e74285d7b4ec2349190ebe3056985 to your computer and use it in GitHub Desktop.
Toying around with indexed traversals in Monocle
package monocle
import scalaz._, Scalaz._
import Indexable._
abstract class IPTraversal[I, S, T, A, B] {
def modifyF[
F[_]: Applicative,
P[_, _]: Indexable[I, ?[_, _]]](
f: P[A, F[B]])(s: S): F[T]
def getAll(s: S): List[(I, A)] =
modifyF[Const[List[(I, A)], ?], Indexed[I, ?, ?]](
Indexed(i => a => Const(List((i, a)))))(s).getConst
def modify(f: I => A => B)(s: S): T =
modifyF[Id, Indexed[I, ?, ?]](Indexed(f))(s)
}
object IPTraversal {
def both[A, B] = new IPTraversal[Boolean, (A, A), (B, B), A, B] {
def modifyF[
F[_]: Applicative,
P[_, _]: Indexable[Boolean, ?[_, _]]](
f: P[A, F[B]])(s: (A, A)): F[(B, B)] =
index(f)(true)(s._1).tuple(index(f)(false)(s._2))
}
}
trait Indexable[I, P[_, _]] {
def index[A, B](pab: P[A, B])(i: I)(a: A): B
}
object Indexable {
implicit def functionIndexable[I]: Indexable[I, ? => ?] =
new Indexable[I, ? => ?] {
def index[A, B](f: A => B)(i: I)(a: A) = f(a)
}
case class Indexed[I, A, B](runIndexed: I => A => B)
implicit def indexedIndexable[I]: Indexable[I, Indexed[I, ?, ?]] =
new Indexable[I, Indexed[I, ?, ?]] {
def index[A, B](ix: Indexed[I, A, B])(i: I)(a: A) = ix.runIndexed(i)(a)
}
def index[I, P[_, _], A, B](
pab: P[A, B])(
i: I)(
a: A)(implicit
I: Indexable[I, P]): B =
I.index(pab)(i)(a)
}
@neutropolis
Copy link
Author

Using indexed traversal interface:

scala> import monocle.IPTraversal._
import monocle.IPTraversal._

scala> both[String, Int].getAll(("hello", "world"))
res0: List[(Boolean, String)] = List((true,hello), (false,world))

scala> both[String, Int].modify(b => s => if (b) s.length else 0)(("hello", "world"))
res1: (Int, Int) = (5,0)

@Softsapiens
Copy link

Hacking on the AVE:

    def plist[A, B] = new IPTraversal[Int, List[A], List[B], A, B] {
      def modifyF[
        F[_]: Applicative,
        P[_, _]: Indexable[Int, ?[_, _]]](
        f: P[A, F[B]])(s: List[A]): F[List[B]] =
      {
        val app = Applicative[F]

        def loop(i: Int, l: List[A], acc: F[List[B]]): F[List[B]] =
          l match {
            case Nil => acc
            case x::xs =>
              loop(i+1, xs,
                   app.apply2(acc, app.map(indexHelper(f)(i)(x))(List(_))){_ ++ _})
          }
        loop(1, s, Applicative[F].point(List()))
      }
    }

Running it:

  plist[String, String].getAll(List("hi", "traversal"))  // List((1,hi), (2,traversal))
  plist[String, String].modify(i => s => if (i % 2 ==0) s.toUpperCase else s)(List("hi", "traversal"))   // List("hi", "TRAVERSAL")

Thanks for all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment