How to simplify nested map calls?

前端 未结 3 2033
独厮守ぢ
独厮守ぢ 2021-01-11 17:33

Suppose I have a few nested functors, e.g. List[Option[Int]] and need to call the map of the most inner one.

Now I am using nested m

相关标签:
3条回答
  • 2021-01-11 17:47

    Yes, this is possible with scalaz.Functor:

    scala> import scalaz.Functor
    import scalaz.Functor
    
    scala> import scalaz.std.list._
    import scalaz.std.list._
    
    scala> import scalaz.std.option._
    import scalaz.std.option._
    
    scala> Functor[List].compose[Option].map(List(some(0), some(1)))(_ + 1)
    res1: List[Option[Int]] = List(Some(1), Some(2))
    

    However, this is longer than to simply call map with a nested map. If you often map nested structures, you can create helper functions:

    def map2[F[_], G[_], A, B](fg: F[G[A]])(f: A => B)
      (implicit F0: Functor[F], G0: Functor[G]): F[G[B]] =
      F0.map(fg)(g => G0.map(g)(f))
    
    def map3[F[_], G[_], H[_], A, B](fg: F[G[H[A]]])(f: A => B)
      (implicit F0: Functor[F], G0: Functor[G], H0: Functor[H]): F[G[H[B]]] =
      F0.map(fg)(g => G0.map(g)(h => H0.map(h)(f)))
    
    ...
    

    Usage:

    scala> map2(List(some(0), some(1)))(_ + 1)
    res3: List[Option[Int]] = List(Some(1), Some(2))
    
    scala> map3(List(some(some(0)), some(some(1))))(_ + 1)
    res4: List[Option[Option[Int]]] = List(Some(Some(1)), Some(Some(2)))
    
    0 讨论(0)
  • 2021-01-11 18:01

    If you have a lot of nested functors and you don't want to flatten them (i.e. they're not monads or you don't want to use them as monads) - then lenses may help. There is quicklens implementation, which supports traversable lenses : http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/.

    Example (sorry didn't try to compile it):

    modify(opts)(_.each.each).using(_ + 1)
    

    Anyway, you have to specify nesting level, but you don't have to nest functions here. And it's enough to specify it once, like (conceptual example, didn't check):

    def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
    
    md2[Int](opts).using(_ + 1)     
    
    0 讨论(0)
  • From the question I understood that you are tying to prune the list iterator e.i. remove upper levels of list in that case you can use flatten which convert list of lists into a single list.

    I will be removing few layers of list using flatten

    Code:-

    val lists = List( 
                        List( 
                            List(
                                    List("1"),List("2")
                                ),
                            List(
                                    List("3"),List("4") 
                                ) ,
                            List(
                                    List("a"),List("b")
                                ),
                            List(
                                    List("c"),List("d")
                                ) 
                                )
                      )
    
    val innerVal = lists.flatten.foreach(println)
    

    results :-

    List(List(1), List(2))
    List(List(3), List(4))
    List(List(a), List(b))
    List(List(c), List(d))
    
    0 讨论(0)
提交回复
热议问题