【问题标题】:How to pipe the result of a transformation chain to a function?如何将转换链的结果通过管道传递给函数?
【发布时间】:2013-12-01 06:00:44
【问题描述】:

我想写一个转换链,最后有一个块,我在不使用变量的情况下对结果集合做一些事情。 集合上是否有一个高阶函数只提供调用它的集合给所提供的函数?

Query( ... )
  .map { ... }
  .filter { ... }
  .combinations(2)
  .pipeTo { col =>
     ...
     consolidate(col)
  }

当然,对于单个函数调用,可以这样做:

consolidate(
  Query()
    .map { ... }
    .filter { ... }
    .combinations(2)
)

但前者对我来说更自然,并且允许例如用于轻松注入一些条件。

我一直在使用的解决方法是在末尾放置一个匹配子句:

Query()
  .map { ... }
  .filter { ... }
  .combinations(2)
  match { case lst =>
    ...
    consolidate(lst)
  }

但由于这种模式经常出现,我想知道写这个的惯用方式是什么。

【问题讨论】:

  • 这可能有点傻,但你能不能只在你的整个链条上调用合并? consolidate(Query().map(...).filter(...).combinations(2)) 看起来和你上一个例子做的一样
  • 我在第二个示例中介绍了该选项,但它不等同于 match 示例,因为后者除了调用“合并”函数之外还允许进行其他处理。

标签: scala higher-order-functions


【解决方案1】:

也许最惯用的方法是使用所谓的Pimp My Library Pattern,它允许通过隐式类转换向任何类添加扩展方法。

例如,要将consolidate 方法添加到Lists,您可以这样写:

object ListExtensions {
  implicit class ConsolidatableList[T](val lst: List[T]) extends AnyVal {
    def consolidate = ??? // Do whatever you want with the List lst
  }
}

import ListExtensions._

List(1,2,3)
  .map(x => x * x)
  .consolidate

如果您真的希望能够在链中的任意对象上调用任意函数,您甚至可以像在 F# 中那样定义“管道”运算符:

object Extensions {
  implicit class PipelineExtension[T](val obj: T) extends AnyVal {
    def |>[S](f: T => S): S = f(obj)
  }
}

import Extensions._

List(1,2,3)
  .map(x => x * x) 
  .|> (consolidate)

Query( ... )
  .map { ... }
  .filter { ... }
  .combinations(2)
  .|> { col =>
     ...
     consolidate(col)
  }

|> 运算符的行为类似于您定义的 pipeTo 方法。

基本上,这是通过创建从您的类型到使用您定义的各种扩展方法的类型的隐式转换来实现的。 AnyVal 使扩展类成为一个值类,因此它的使用几乎没有运行时成本。

【讨论】:

  • 所以我认为 Scala 库不提供任何形式的此类运算符?
  • 我不知道。据推测,最好像第一个示例中那样定义扩展方法,或者定义中间vals 来保存部分结果,然后在这些中间vals 上调用函数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-24
  • 2010-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多