2010-02-01 9 views
7

Stavo leggendo questo articolo da Tomas Petricek, e parlano del pipelining |> come nell'esempio dato:In F #, cosa significa pipelining?

 
> let nums = [1; 2; 3; 4; 5];; 
val nums : list<int> 

> let odds_plus_ten = 
     nums 
     |> List.filter (fun n-> n%2 <> 0) 
     |> List.map (add 10) 
val odds_plus_ten : list<int> = [11; 13; 15];; 

Cosa significa pipelining? Inizialmente, pensavo che fosse simile a un'istruzione della CPU collegata ai core. Puoi spiegare di cosa si tratta e come funziona nel contesto di F #?

Grazie, Cordiali saluti, Tom.

+2

Pensate più come la pipeline in PowerShell o gusci tradizionali (anche se, se si considera che gli oggetti vengono passati è davvero più simile a PowerShell). Non ha nulla a che fare direttamente con la pipeline della CPU :-) – Joey

+0

@Johannes: vuoi dire qualcosa del genere ... cat myfile | più, l'input da uno viene passato all'output per essere elaborato da più? – t0mm13b

+0

Esattamente. Anche se, come detto, l'analogia della shell UNIX è piuttosto errata per questo. – Joey

risposta

11

Pipelining significa passare i risultati di una funzione a un'altra funzione. Nell'esempio che dai "numeri" è passato il filtro List.Filter, i risultati filtrati vengono passati a List.Map.

Maggiori informazioni qui: http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6

+0

@Steve: Grazie per il link, esamineremo una domanda veloce: come fa il pipelining a sapere quando smettere di passare le informazioni da una all'altra? :) Grazie. – t0mm13b

+0

@Steve: questo è un buon collegamento! Tieni questo segnalibro quando termino l'articolo di Tomas Petricek! Mi sta friggendo il cervello in questo momento con la shell interattiva F # qui sulla mia estremità ... – t0mm13b

+0

Scusa, sto solo inserendo F # anche così non sono sicuro di poter davvero rispondere alla tua domanda successiva. Non penso che tu possa "fermare" il pipelining, penso che tutti i risultati della prima funzione siano passati al prossimo. –

13

In un certo senso non c'è niente di speciale pipelining; invece di scrivere f (g (h x)), è possibile scrivere x |> h |> g |> f, che non sembra un miglioramento evidente. Tuttavia, ci sono due punti vale la pena tenere a mente:

  1. A volte l'ordine di lettura è migliore per la versione pipeline: "Prendi x e inviarlo a h, inviare il risultato al g, inviare il risultato al f" può essere più facile da capire di "Applicare f al risultato dell'applicazione di g al risultato dell'applicazione di h a x".
  2. L'inferenza di tipo spesso funziona molto meglio per la versione pipeline. Questa è probabilmente la ragione principale per cui il pipelining è usato così tanto in F #. Poiché l'inferenza di tipo procede da sinistra a destra, funzionerà quando x è un string[], ma non lo sarà Array.map (fun s -> s.Length) x; devi invece fare Array.map (fun (s:string) -> s.Length) x.
2

Verificare Pipelining in F# per una spiegazione.

(Se avete familiarità con la riga di comando UNIX e tubazioni come

cat file1 | sort | head 

è un'idea simile,. Il risultato dell'espressione precedente diventa l'argomento della funzione successiva)

3

Come altri hanno menzionato che la pipeline è più simile a una pipeline di shell UNIX. Ti lasciamo scrivere alcuni input seguiti da operazioni che dovrebbero essere applicate ad esso, invece delle solite chiamate di funzioni annidate. In questo esempio, il codice standard F # sarebbe simile a questa:

let r = List.map (add 10) (List.filter (fun n-> n%2 <> 0) nums) 

Nota che l'ingresso nums è profondamente annidato nell'espressione e non è facile vedere che viene prima filtrata e poi proiettata. Usando il pipelining, puoi scrivere il codice in modo diverso, ma significherà esattamente la stessa cosa.

Il trucco è che l'operatore di pipelining accetta due parametri utilizzando la notazione infisso (ad esempio x |> f). Il parametro x verrà passato come ultimo argomento a una funzione a destra (f). È possibile utilizzare il pipelining con qualsiasi # funzioni F:

let sinOne = 1.0 |> sin 

let add a b = a + b 
let r = 10 |> add 5 // it doesn't always make code more readable :-) 

Un punto importante su F # operatore pipelining è che non è un qualsiasi speciale built-in funzione della lingua.Si tratta di un semplice operatore personalizzato che è possibile definire da soli:

let (|>) x f = f x 

// Thanks to operator associativity rules, the following: 
let r = 1.0 |> sin |> sqrt 
// ...means this: 
let r = (1.0 |> sin) |> sqrt 
+2

Mi sorprende che la definizione di un operatore così potente e utile sia così banale. – Benjol