【问题标题】:How to simplify nested map calls?如何简化嵌套地图调用?
【发布时间】:2015-07-08 05:25:24
【问题描述】:

假设我有几个嵌套的仿函数,例如List[Option[Int]],需要调用最里面的map

现在我使用嵌套的maps:

scala> val opts: List[Option[Int]] = List(Some(0), Some(1))
opts: List[Option[Int]] = List(Some(0), Some(1))

scala> opts.map(o => o.map(_ + 1))
res0: List[Option[Int]] = List(Some(1), Some(2))

例如,如果我有 3 个嵌套级别怎么办?
嵌套 maps 有什么简单的替代方法吗?

【问题讨论】:

    标签: scala functor


    【解决方案1】:

    是的,这可以通过 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))
    

    但是,这比使用嵌套的 map 简单地调用 map 要长。如果你经常映射嵌套结构,你可以创建辅助函数:

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

    用法:

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

    【讨论】:

    • 嗨@ZhekaKozlov - 我试图理解你上面提到的辅助函数:- F0.map(fg)(g => G0.map(g)(f)) 这是否意味着我们首先在F0.map(fg) 中创建一个type F 的函子作为辅助函数 map2 不知道 F[G[A]]Functor 类型,一旦创建了仿函数,我们将 F 中的类型拉到 G 中,然后创建它的仿函数,然后应用函数 f?
    【解决方案2】:

    如果您有很多嵌套的仿函数并且您不想将它们展平(即它们不是 monad 或者您不想将它们用作 monad) - 那么镜头可能会有所帮助。有 quicklens 实现,它支持可遍历的镜头:http://www.warski.org/blog/2015/03/quicklens-traversing-options-and-lists/

    示例(抱歉没有尝试编译):

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

    无论如何,您必须指定嵌套级别,但您不必在这里嵌套函数。并且指定一次就足够了,比如(概念示例,没有检查):

    def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)
    
    md2[Int](opts).using(_ + 1)     
    

    【讨论】:

      【解决方案3】:

      从我了解到的问题中,您要修剪列表迭代器 e.i.在这种情况下删除列表的上层,您可以使用 flatten 将列表列表转换为单个列表。

      我将使用flatten删除几层列表

      代码:-

      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)
      

      结果:-

      List(List(1), List(2))
      List(List(3), List(4))
      List(List(a), List(b))
      List(List(c), List(d))
      

      【讨论】:

      • 我没有假设我的函子是单子,所以不能使用flatten
      猜你喜欢
      • 1970-01-01
      • 2019-12-28
      • 2019-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 1970-01-01
      • 2018-06-17
      相关资源
      最近更新 更多