Lui*_*hys 7 functional-programming scala scala-collections
而不是xs map f map g它更有效地编写xs map { x => g(f(x)) },并且类似地用于多个filter操作.
如果我flatMap连续两个或更多,有没有办法将它们合二为一,那可能更有效率?例如
def f(x: String) = Set(x, x.reverse)
def g(x: String) = Set(x, x.toUpperCase)
Set("hi", "bye") flatMap f flatMap g
// Set(bye, eyb, IH, BYE, EYB, ih, hi, HI)
Run Code Online (Sandbox Code Playgroud)
Pet*_*lák 11
为了进行这样的转换,我们需要使用操作所具有的一些标识.例如,正如您所写,map具有身份
map f ? map g ? map (f ? g)
Run Code Online (Sandbox Code Playgroud)
(其中?代表函数组合 - 参见Function1 .compose(...);并?代表表达式的等价).这是因为类map可以被视为仿函数,因此任何合理的实现都map必须保留此属性.
另一方面,拥有flatMap并具有如何创建某种单元素实例(如创建单例Set)的类通常会形成一个monad.所以我们可以尝试从monad规则中推导出一些变换.但我们可以推断出重复应用的唯一身份flatMap是
(set flatMap f) flatMap g ? x flatMap { y => f(y) flatMap g }
Run Code Online (Sandbox Code Playgroud)
这是一种关联关系用于flatMap组合物.这对优化计算没有多大帮助(实际上它可能会使情况变得更糟).因此,结论是,没有类似的一般"优化"身份flatMap.
底线是:给出的每个函数为它应用的每个元素Set.flatMap创建一个新函数Set.除非我们完全忘记使用合成flatMap并以某种不同的方式解决问题,否则我们无法避免创建这样的中间集.通常这是不值得的,因为编写flatMap(或使用for(...) yield ..)更清晰,更易读,并且速度权衡通常不是一个大问题.
在scalaz有组成样功能的方式a -> m b和b -> m c进入a -> m c(如这里的功能,从String至Set[String]).顺便说一句,它们被称为Kleisli功能.在haskell中,只需使用>=>这些函数即可完成.在scala中,你必须更加冗长(顺便说一句,我已经改变了一些例子:我无法使用它Set,所以我已经使用过了List):
scala> import scalaz._, std.list._
import scalaz._
import std.list._
scala> def f(x: String) = List(x, x.reverse)
f: (x: String)List[String]
scala> def g(x: String) = List(x, x.toUpperCase)
g: (x: String)List[java.lang.String]
scala> val composition = Kleisli(f) >=> Kleisli(g)
composition: scalaz.Kleisli[List,String,java.lang.String] = scalaz.KleisliFunctions$$anon$18@37911406
scala> List("hi", "bye") flatMap composition
res17: List[java.lang.String] = List(hi, HI, ih, IH, bye, BYE, eyb, EYB)
Run Code Online (Sandbox Code Playgroud)