【问题标题】:'tee' operation on Scala's option type?对 Scala 选项类型的“三通”操作?
【发布时间】:2017-02-11 16:45:31
【问题描述】:

Scala 标准库中的Option 是否有某种“tee”操作?我能找到的最好的是foreach,但它的返回类型是Unit,因此它不能被链接。

这就是我要找的:给定一个Option 实例,如果选项不为空(Some[A]),则执行一些对其值有副作用的操作,否则什么也不做;在任何情况下都返回选项。

我有一个使用隐式类的自定义实现,但我想知道是否有更常见的方法可以在没有隐式转换的情况下做到这一点:

object OptionExtensions {
  implicit class TeeableOption[A](value: Option[A]) {
    def tee(action: A => Unit): Option[A] = {
      value foreach action
      value
    }
  }
}

示例代码:

import OptionExtensions._

val option: Option[Int] = Some(42)
option.tee(println).foreach(println) // will print 42 twice

val another: Option[Int] = None
another.tee(println).foreach(println) // does nothing

有什么建议吗?

【问题讨论】:

标签: scala functional-programming


【解决方案1】:

为了避免隐式转换,您可以将函数组合与 k-combinator 一起使用,而不是使用方法链接。 k-combinator 为您提供了一种惯用的方式来传达您将要执行副作用的事实。

这是一个简短的例子:

object KCombinator {
  def tap[A](a: A)(action: A => Any): A = {
    action(a)
    a
  }
}

import KCombinator._

val func = ((_: Option[Int]).getOrElse(0))
  .andThen(tap(_)(println))
  .andThen(_ + 3)
  .andThen(tap(_)(println))

如果我们用Option(3) 的参数调用我们的函数,结果将是一个值为6 的Int 这就是控制台的样子:

3

6

【讨论】:

  • ... 除了它不起作用。 :) 调用 func(None) 会导致 0 和 3 打印到标准输出,这不是必需的。尽管如此,我还是接受了答案,因为这个想法是正确的,并且使用 def tap[A](action: A => Any)(value: A): Option[A] = { action(value); Some(value) } 可以解决问题:如果选项不为空,option.flatMap(tap(println)).foreach(println) 会打印 42 两次;否则它什么也不做。
  • 打印 0 和 3 只是因为我调用了 getOrElse(0)。返回 Some(value) 是错误的,因为你最终会得到一个嵌套的 Option of Option of ... 你会得到不是你想要的想法。我认为在抽头本身内部短路没有多大意义。您可以在点击动作中对数学进行模式化,以获得您正在寻找的完全相同的行为。
  • 没错,但我认为这取决于构图的完成方式。从这个意义上说,我不认为返回 Some(value) 本质上是错误的,只有在使用 andThen 时。
【解决方案2】:

简单地使用map,让你的副作用函数符合action: A => A而不是action: A => Unit

 def tprintln[A](a: A): A = {
    println(a)
    a
 }
 another.map(tprintln).foreach(println) 

【讨论】:

    【解决方案3】:

    在标准库中没有实现这一点的现有方法,因为在函数式编程中副作用被最小化和隔离。根据您的实际目标,有几种不同的方式可以习惯性地完成您的任务。

    在执行大量println 命令的情况下,您通常会将它们收集到一个集合中,然后在最后执行一个foreach println,而不是将它们散布在整个算法中。这将副作用降至最低,从而将影响降至最低。这与任何其他副作用有关。试着想办法把它挤到尽可能小的空间里。

    如果您尝试链接一系列“操作”,您应该查看futures。 Futures 基本上将一个动作视为一个值,并提供许多有用的函数来处理它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多