2013-08-29 9 views
5

Ho due funzioni che sono una composizione di funzioni pure. La prima funzione prende un pacco, costruisce una casa su di esso, e scattare una foto per fare pubblicità in una rivista:Come evitare il calcolo non necessario quando si compongono funzioni pure in un linguaggio funzionale?

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

La seconda funzione prende anche un pacco, costruisce una casa su di esso, e aggiunge una finitura touch to it:

È chiaro che le due funzioni sono pure pure, poiché sono una composizione di funzioni pure. Ora ho un pacco, diciamo niceParcel e voglio applicare entrambe le funzioni ad esso. Tuttavia, voglio evitare che le prime tre sottofunzioni vengano calcolate due volte in quanto impiegano un grande tempo per il calcolo e sono condivise tra le due funzioni.

Come si effettua il refactoring del mio codice, quindi si evitano questi calcoli inutili, pur mantenendo queste belle funzioni pure che hanno un significato chiaro?

+1

Se 'parcel' non è un tipo generico, quindi è possibile rendere il codice più idiomatico con' let buildAnd ... = inspect >> buildWalls >> ... >> advertise' (e con indentazione corretta) –

+1

Per quanto riguarda la domanda, perché non dividere le due funzioni in tre funzioni denominate 'build',' advertise' e ​​'completeHouse'? –

+0

Formano un'entità che può essere utilizzata in diverse parti del programma. Certo che possono essere divisi, ma poi questa entità è persa. In tal caso, se vuoi usarli, dovresti conoscere il funzionamento interno, vale a dire che è prima costruito e poi completato o pubblicizzato. Voglio evitare che tu debba conoscere il funzionamento interno. – Tuur

risposta

5

Come altri menzionati nei commenti, ritengo che l'approccio migliore sia trasformare la parte comune in una funzione build. Anche se non si intende utilizzare la funzione per altri scopi, questo è un modo pulito per strutturare il codice funzionale.

In F #, è possibile definire un tipo che rappresenta una casa parzialmente costruita, ma non espone i suoi interni. Ciò significa che i chiamanti della vostra biblioteca possono utilizzare build di costruire una casa parzialmente costruita, ma allora l'unica cosa che possono fare con esso è quello di utilizzare le due funzioni che hai fornito:

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

    let buildAndAdvertiseHouse house = 
    house 
    |> takePhoto 
    |> advertise 

    let buildAndCompleteHouse house = 
    house 
    |> paintWalls 
    |> addFurniture 

si può nascondere il fatto che uno ha bisogno di costruire una casa prima di poter pubblicizzare & completarlo in vari modi. Ad esempio, se in genere esegui entrambe le operazioni contemporaneamente, puoi definire una funzione che chiama tutte e tre le funzioni e l'utente della tua libreria può semplicemente usarlo o imparare un po 'di più sulla costruzione di una casa e utilizzare le tre funzioni se bisogno di un controllo più fine.

Un altro approccio sarebbe semplicemente racchiudere la funzionalità in un tipo semplice. F # è un misto di stile funzionale e orientato agli oggetti, quindi non c'è nulla di veramente sbagliato nell'avere un tipo che esegue la parte comune una volta sola e mantiene uno stato.

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

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

    member x.BuildAndCompleteHouse() = 
    house 
    |> paintWalls 
    |> addFurniture 

Questo va bene in F #, ma penso che io preferirei l'approccio funzionale con una funzione build.

Problemi correlati