如何简化嵌套地图调用?

Mic*_*ael 10 scala functor

假设我有一些嵌套的仿函数,例如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))
Run Code Online (Sandbox Code Playgroud)

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

Zhe*_*lov 9

是的,这可以通过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))
Run Code Online (Sandbox Code Playgroud)

但是,这比仅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)))

...
Run Code Online (Sandbox Code Playgroud)

用法:

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)))
Run Code Online (Sandbox Code Playgroud)


dk1*_*k14 5

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

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

modify(opts)(_.each.each).using(_ + 1)
Run Code Online (Sandbox Code Playgroud)

无论如何,您必须指定嵌套级别,但您不必在此处嵌套函数.并且它足以指定一次,如(概念示例,未检查):

def md2[T]: (l: List[Option[T]]) => modify(l)(_.each.each)

md2[Int](opts).using(_ + 1)     
Run Code Online (Sandbox Code Playgroud)