以惯用的方式组合选项

Hen*_*son 1 functional-programming scala

我将在Scala中编写这个,但它更像是一个函数式编程问题.

我有

def foo(x: A): Option[B]
Run Code Online (Sandbox Code Playgroud)

def bar(x:B, y:B): C
Run Code Online (Sandbox Code Playgroud)

执行以下操作的最佳方法是什么:

def compose(x:A, y:A): Option[C]
Run Code Online (Sandbox Code Playgroud)

如果foo(y)的foo(x)为None,则compose(x,y)为None,否则compose(x,y)为bar(foo(x).get,foo(y).get) .我能想到的最好的是:

foo(a).flatMap( aRes => foo(b).map( bRes => bar(a,b)))
Run Code Online (Sandbox Code Playgroud)

Tra*_*own 5

以下是您当前解决方案的语法糖:

def compose(x: A, y: A): Option[C] = for {
  fx <- foo(x)
  fy <- foo(y)
} yield bar(fx, fy)
Run Code Online (Sandbox Code Playgroud)

有时,这种方法比写出更好的flatMapmap,有时事实并非如此.你可能会发现你很快就会对这种事情产生强烈的偏好.要么被认为是惯用的Scala.

但是,从功能编程的角度来看,你已经表明你对这个问题更感兴趣,但值得注意的是,上述解决方案在某种意义上来说是过度的.他们利用了Optionmonadic 这一事实,但是对于这个操作,你实际上并不需要所有这些功能 - Option具有应用程序仿函数实例的事实就足够了.非常非正式地总结,flatMap给你在这里不需要的排序,因为计算fy不依赖于计算fx.使用applicative functor Option可以更清楚地捕获两个计算之间没有依赖关系的事实.

斯卡拉标准库不提供任何类型的应用性函子的表示,但Scalaz确实,与Scalaz你可以写你的方法是这样的(见我的回答的"附录" 这里的语法的一些讨论):

import scalaz._, Scalaz._

def compose(x: A, y: A): Option[C] = (foo(x) |@| foo(y))(bar)
Run Code Online (Sandbox Code Playgroud)

这将产生与上面的实现相同的结果,但使用更合适的抽象.