5

純粋関数の合成である 2 つの関数があります。最初の関数は区画を受け取り、その上に家を建て、雑誌で宣伝するために写真を撮ります。

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

2 番目の関数も区画を受け取り、その上に家を建て、仕上げを加えます。

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

2 つの関数も純粋関数の合成であることは明らかです。今、区画があり、niceParcel両方の機能をそれに適用したいとします。ただし、最初の 3 つのサブ関数は計算に時間がかかり、2 つの関数間で共有されるため、2 回計算されることは避けたいと思います。

コードをリファクタリングして、これらの不要な計算を回避し、明確な意味を持つこれらの素晴らしい純粋な関数を維持するにはどうすればよいですか?

4

1 に答える 1

5

buildコメントで他の人が述べたように、最善のアプローチは共通部分を関数に変えることだと思います。関数を他の目的で使用するつもりがない場合でも、これは機能コードを構造化するためのクリーンな方法です。

F# では、部分的に建てられた家を表す型を定義できますが、その内部は公開されません。これは、ライブラリの呼び出し元がbuild部分的に構築された家を建てるために使用できることを意味しますが、それでできることは、提供された 2 つの関数を使用することだけです。

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

  let buildAndAdvertiseHouse house = 
    house
    |> takePhoto
    |> advertise

  let buildAndCompleteHouse house = 
    house
    |> paintWalls
    |> addFurniture

さまざまな方法で宣伝して完成させる前に、家を建てる必要があるという事実を隠すことができます。たとえば、通常、両方の操作を一度に行う場合、3 つの関数すべてを呼び出す関数を定義できます。ライブラリのユーザーは、これを使用するか、家の建設についてもう少し学び、必要に応じて 3 つの関数を使用できます。より細かい制御が必要です。

もう 1 つのアプローチは、単純な型で機能をラップすることです。F# には関数型とオブジェクト指向のスタイルが混在しているため、共通部分を 1 回実行して何らかの状態を保持する型を使用しても、実際には何の問題もありません。

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 に答える