我将在Scala中编写这个,但它更像是一个函数式编程问题.
我有
def foo(x: A): Option[B]
和
def bar(x:B, y:B): C
执行以下操作的最佳方法是什么:
def compose(x:A, y:A): Option[C]
如果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)))
Travis Brown.. 5
以下是您当前解决方案的语法糖:
def compose(x: A, y: A): Option[C] = for { fx <- foo(x) fy <- foo(y) } yield bar(fx, fy)
有时,这种方法比写出更好的flatMap
和map
,有时事实并非如此.你可能会发现你很快就会对这种事情产生强烈的偏好.要么被认为是惯用的Scala.
但是,从功能编程的角度来看,你已经表明你对这个问题更感兴趣,但值得注意的是,上述解决方案在某种意义上来说是过度的.他们利用了Option
monadic 这一事实,但是对于这个操作,你实际上并不需要所有这些功能 - 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)
这将产生与上面的实现相同的结果,但使用更合适的抽象.