在函数式语言中编写纯函数时如何避免不必要的计算?

时间:2013-08-29 07:53:30

标签: .net f# functional-programming numerical-computing

我有两个由纯函数组成的函数。 第一个功能需要一个包裹,在其上建一个房子,然后拍照以在杂志上刊登广告:

let buildAndAdvertiseHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> takePhoto
    |> advertise

第二个功能还包含一个包裹,在其上建造房屋,并为其添加画龙点睛:

let buildAndCompleteHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> paintWalls
    |> addFurniture

很明显,这两个函数也是纯粹的,因为它们是纯函数的组合。现在我有一个包裹,让我说niceParcel,我想将两个功能都应用到它。但是,我想避免前三个子函数计算两次,因为它们需要花费大量时间进行计算,并且它们在两个函数之间共享。

如何重构我的代码,以避免这些不必要的计算,同时保留这些具有明确含义的纯函数?

1 个答案:

答案 0 :(得分:5)

正如评论中提到的其他人一样,我认为最好的方法是将公共部分转变为build函数。即使您不打算将该函数用于其他目的,这也是构建功能代码的简洁方法。

在F#中,您可以定义表示部分构建的房屋的类型,但不会暴露其内部。这意味着您的库的调用者可以使用build来构建一个部分构建的房子,但是他们唯一能做的就是使用您提供的两个函数:

module Houses = 
  type House = private HouseData of <whatever>
  let build parcel = (...)

  let buildAndAdvertiseHouse house = 
    house
    |> takePhoto
    |> advertise

  let buildAndCompleteHouse house = 
    house
    |> paintWalls
    |> addFurniture

你可以隐藏这样一个事实,即你需要建立一个房子才能做​​广告和宣传。以各种方式完成它。例如,如果您通常同时执行两个操作,那么您可以定义一个调用所有三个函数的函数 - 并且您的库的用户可以使用它或者了解更多关于房屋建筑的信息,如果它们可以使用这三个函数需要更好的控制。

另一种方法是将功能包装在一个简单的类型中。 F#混合功能和面向对象的风格,因此拥有一个运行公共部分并保持某种状态的类型没有任何问题。

type House(parcel) = 
  let house = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof

  member x.BuildAndAdvertiseHouse()
    house
    |> takePhoto
    |> advertise

  member x.BuildAndCompleteHouse() = 
    house
    |> paintWalls
    |> addFurniture

这在F#中很好,但我认为我更喜欢使用build函数的函数方法。