在Scala中使用List作为monad

时间:2015-05-18 09:30:33

标签: scala

我想知道在List上如果它不为空则应用某些操作的惯用方法是什么,如果列表为空则返回空ListNil)。

  val result= myList match  {
     case Nil => Nil // this one looks bad for me
     case nonEmpty =>  myService.getByFilters(nonEmpty)
  }

在列表上使用map操作会触发循环,但我想为map类型获得与Option相同的结果 - 即如果List只执行一次操作非空,如果List为空,则不执行任何操作

4 个答案:

答案 0 :(得分:3)

我认为你的设计也许并不合适。您应该只能将任何列表传递到getByFilters函数,它应该只处理任何长度的列表。所以不应该进行这类检查。

如果无法进行设计更改,if

没有任何问题
val result = if(myList.isEmpty) Nil else myService.getByFilters(myList)

这是惯用的,因为if返回值。也许还有其他干净的方式,我不知道。

如果您只想要非空列表参数,可以使用HList,或者您可以使用此技巧:

def takesNonEmptyList[T](head: T, tail: T *): List[T] = head :: tail.toList

你可以做一些虚假的事情,使它看起来像惯用语,但我不推荐它。这是不清楚和不必要的并发症:

def getByFilters(xs: List[Int]) = xs.filter(_ % 2 == 0)
val res = l.headOption.map(_ :: l.tail).map(getByFilters).getOrElse(Nil)
println(res)

打印List(2, 4)

答案 1 :(得分:0)

如果你真的想要它,你可以实现自己的语义:

  implicit class MySpecialList[T](xs: List[T]) {
    def mapIfNotEmpty[R](f: List[T] ⇒ List[R]): List[R] =
      if (xs.isEmpty) Nil else f(xs)
  }

  def getStuff(xs: List[Int]) = xs.map(_ + " OK")

  val x: List[Int] = List(1,2,3)
  val y: List[Int] = List()

  def main(args: Array[String]): Unit = {
    val xx = x.mapIfNotEmpty(getStuff) // List("1 OK", "2 OK", "3 OK")
    val yy = y.mapIfNotEmpty(getStuff) // List()
  }

答案 2 :(得分:0)

headOption中有方法List,因此您可以使用选项语义将List提升为Option[List]

import scala.collection.TraversableLike

implicit class TraversableOption[T <: TraversableLike[_, T]](traversable: T) {
  def opt: Option[T] = traversable.headOption.map(_ => traversable)
}

您可以将其用作:

val result = myList.opt.fold[List[Int]](Nil)(myService.getByFilters)

答案 3 :(得分:0)

通过单独调用每个过滤器服务,

myList.flatMap(filter => myService.getByFilters(List(filter)))

如果myList为空,则会获得一个空列表。如果性能可能是一个问题,请考虑使用

的并行版本
myList.par