5

我有两个由纯函数组成的函数。第一个函数取一个地块,在上面盖房子,然后拍张照片在杂志上做广告:

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

第二个函数也需要一个地块,在上面盖房子,然后给它画龙点睛:

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

很明显,这两个函数也是纯函数,因为它们是纯函数的组合。现在我有一个包裹,比方说niceParcel,我想将这两个功能都应用到它上面。但是,我想避免前三个子函数被计算两次,因为它们需要很长时间来计算并且它们在两个函数之间共享。

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

4

1 回答 1

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函数的函数式方法。

于 2013-08-29T14:17:01.653 回答