在Scala中将列表用作monad

在Scala中将列表用作monad,scala,Scala,我想知道在列表上应用一些操作(如果它不是空的)的惯用方法是什么,如果列表是空的,则返回空的列表(Nil) val result= myList match { case Nil => Nil // this one looks bad for me case nonEmpty => myService.getByFilters(nonEmpty) } 只需在列表上使用map操作将触发循环,但我希望在选项类型上实现与map相同的结果-即,如果list为

我想知道在
列表
上应用一些操作(如果它不是空的)的惯用方法是什么,如果列表是空的,则返回空的
列表
Nil

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

只需在列表上使用
map
操作将触发循环,但我希望在
选项
类型上实现与
map
相同的结果-即,如果
list
为非空,则只执行一次,如果
list
为空,则不执行任何操作

我认为您的设计可能不太正确。您应该能够将任何列表传递到
getByFilters
函数中,并且它应该只处理任何长度的列表。因此,应该没有必要进行此类检查

如果不可能进行设计更改,则
没有问题,如果

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)

打印
列表(2,4)

如果您确实需要,您可以实现自己的语义:

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

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

import scala.collection.TraversableLike

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

通过分别调用每个筛选器服务

myList.flatMap(filter => myService.getByFilters(List(filter)))
如果
myList
为空,则它将获取一个空列表。如果性能可能是一个问题,也要考虑一个具有

的并行版本。
myList.par

是的,我想在
myService#getByFilters
中移动此逻辑,但后来决定从该方法返回空列表是不正确的,因为在空列表参数列表(过滤器列表)的情况下,它将返回所有值而不应用过滤器。所以我决定,如果列表为空,则在
myService#getByFilters
中抛出异常更为正确。关心空的参数列表是客户机代码的责任。注意,在这种上下文中说“将列表用作monad”是不正确的。List monad有一个特定的定义,它的
fmap
函数是
map
。别的东西既不是单子也不是函子。
myList.par