【问题标题】:How to avoid unnecessary computation when composing pure functions in a functional language?用函数式语言编写纯函数时如何避免不必要的计算?
【发布时间】:2013-08-29 07:53:30
【问题描述】:

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

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

第二个函数也是取一个地块,在上面盖房子,然后画龙点睛:

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

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

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

【问题讨论】:

  • 如果parcel 不是泛型类型,那么您可以使用let buildAnd... = inspect >> buildWalls >> ... >> advertise 使代码更惯用(并使用适当的缩进)
  • 关于这个问题,为什么不将你的两个函数拆分为三个函数,分别命名为buildadvertisecompleteHouse
  • 它们形成一个实体,可用于程序的不同部分。当然它们可以被拆分,但随后这个实体就丢失了。在那种情况下,如果你想使用它们,你就必须知道它的内部运作,即它是先建造的,然后完成或宣传。我想避免你必须知道内部工作原理。
  • 排除build
  • 如果您不想将函数分解为单独的部分,这从您的 cmets 中可以明显看出,那么您可能应该对计算密集型函数使用一些记忆技术。

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


【解决方案1】:

正如其他人在 cmets 中提到的,我认为最好的方法是将公共部分变成 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 函数的函数式方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-07
    • 1970-01-01
    • 2010-10-25
    • 1970-01-01
    • 2010-10-21
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多