2013-08-29 33 views
5

我有兩個函數是純函數的組成部分。 第一個函數需要一個包裹,建立在其上的房屋,並拍攝一張照片來宣傳它在一本雜誌:如何在函數式語言中編寫純函數時避免不必要的計算?

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

第二個功能還需要一個包裹,建立在其上的房屋,並增加了一個整理觸摸它:

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

很明顯,這兩個函數也是純粹的,因爲它們是純函數的組合。現在我有一個包裹,比如說niceParcel,我想將這兩個功能都應用到它。但是,我想避免前三個子函數計算兩次,因爲它們需要很長的時間進行計算,並且它們在兩個函數之間共享。

我該如何重構我的代碼,以避免這些不必要的計算,同時保持這些具有明確含義的漂亮的純函數?

+1

如果'parcel'不是泛型類型,那麼您可以使用'let buildAnd ... = inspect >> buildWalls >> ... >> advertise'(以及合適的縮進)使代碼更具地道性 –

+1

關於這個問題,爲什麼不把你的兩個函數分成三個函數:'build','advertise'和'completeHouse'? –

+0

它們形成一個可用於程序不同部分的實體。當然,他們可以分裂,但是這個實體是失敗的。在這種情況下,如果你想使用它們,你必須知道內部運作,即它是首先建立,然後完成或通告的。我想避免你必須知道內部運作。 – Tuur

回答

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函數。

相關問題