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

Tuu*_*uur 5 .net f# functional-programming numerical-computing

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

let buildAndAdvertiseHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> takePhoto
    |> advertise
Run Code Online (Sandbox Code Playgroud)

第二个功能还包括一个包裹,在它上面建一个房子,并为它添加一个画龙点睛:

let buildAndCompleteHouse parcel = 
    parcel
    |> inspect
    |> buildWalls
    |> buildRoof
    |> paintWalls
    |> addFurniture
Run Code Online (Sandbox Code Playgroud)

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

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

Tom*_*cek 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
Run Code Online (Sandbox Code Playgroud)

您可以隐藏这样一个事实:在您以各种方式宣传和完成房屋之前,您需要建造房屋.例如,如果您通常两者同时进行操作,那么您可以定义调用这三个函数的功能 - 和库的用户可以只使用或学习一些关于房屋建筑,如果他们使用的三个功能需要更好的控制.

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

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

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

  member x.BuildAndCompleteHouse() = 
    house
    |> paintWalls
    |> addFurniture
Run Code Online (Sandbox Code Playgroud)

这在F#中很好,但我认为我更喜欢功能方法build.