2010-02-01 12 views
7

Ben Tomas Petriček tarafından bu makaleyi okuyor ve verilen örnekte olduğu gibi ardışık düzen |> söz:F # içinde, boru hatları ne anlama geliyor?

 
> 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];; 

ardışık düzen ne anlama geliyor? Başlangıçta, çekirdekler içinde boru hattına bağlı bir CPU komutuna benzediğini düşündüm. Ne olduğunu açıklayabilir ve F # bağlamında nasıl çalışır?

sayesinde Saygılarımızla, Tom.

+2

Think daha PowerShell veya geleneksel kabuklarda boru hattı gibi (gerçi, nesneler o PowerShell gerçekten daha akrabadan geçirilir düşünüyor): Bu kendi başınıza tanımlayabilirsiniz Basit bir özel operatörüdür. CPU boru hattı ile doğrudan ilgisi yoktur :-) – Joey

+0

@Johannes: Böyle bir şey demek istiyorsun ... kedi myfile | daha fazla, daha fazla tarafından işlenecek çıktıya bir giriş geçirilir? – t0mm13b

+0

Tam olarak. Ancak, söylendiği gibi, UNIX kabuk benzetmesi bunun için oldukça kusurludur. – Joey

cevap

11

Ardışık başka bir işleve bir fonksiyonun sonucunu geçen anlamına gelir. "Nums" verdiğiniz örnekte, List.Filter öğesinden geçirilir, filtrelenen sonuçlar daha sonra List.Map öğesine iletilir.

burada

diğer bilgiler: boru hattı ile ilgili özel bir şey yok Bazı yönlerden http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6

+0

@Steve: Bağlantı için teşekkürler, buna bakacak olursak, hızlı bir soru - pipelining bilgiyi birinden diğerine aktarmayı ne zaman sona erdireceğini nasıl biliyor? :) Teşekkürler. – t0mm13b

+0

@Steve: Bu iyi bir bağlantı! Tomas Petricek'in makalesini tamamladıktan sonra bu yer imi koyulsun! Beynimi şu anda F # interaktif kabuk ile birlikte benimle kaynatıyor .... – t0mm13b

+0

Üzgünüm, sadece F'ye giriyorum, bu yüzden takip sorularına gerçekten cevap verebileceğime emin değilim. Boru hattını durduramayacağınızı sanmıyorum, bence ilk işlevin tüm sonuçları bir sonrakine geçiyor. –

13

; f (g (h x)) yazmak yerine, x |> h |> g |> f yazabilirsiniz, ki bu belirgin bir gelişme gibi görünmüyor.

  1. Bazen okuma sırası pipelined sürümü için iyidir: "x al ve h göndermek, g sonucunu göndermek, f sonucu gönder" olabilir Ancak, akılda tutmakta fayda iki nokta vardır Anlamaktan daha kolay olunmalıdır, "f, h'den x'e uygulama sonucuna g uygulanması sonucunu uygulayın".
  2. Tip çıkarsama genellikle ardışık versiyonu için çok daha iyi çalışır. Bu muhtemelen boru hatlarının F # içinde çok fazla kullanılmasının en büyük sebebidir. tür kesmesi ilerler soldan sağa beri x string[] olduğunda x |> Array.map (fun s -> s.Length) çalışacaktır ancak Array.map (fun s -> s.Length) x olmaz; bunun yerine Array.map (fun (s:string) -> s.Length) x yapmalısınız.
2

Açıklama için Pipelining in F#'a bakın.

(eğer

cat file1 | sort | head 

benzer bir fikir gibi UNIX komutunu ve borulardan aşina iseniz;. Önceki ifadenin sonucu bir sonraki işlevinin argümanı haline gelir)

3

olarak Bahsedilen diğerleri, pipelining daha çok bir UNIX kabuk boru hattı gibidir. Her zamanki iç içe geçmiş işlev çağrıları yerine, ona uygulanması gereken işlemleri takip eden bir girdi yazalım. Bu örnekte, standart F # kodu şu şekilde görünecektir: Giriş nums derinden ifadesinde yuvalanır ve buna süzüldükten sonra tahmin olduğunu görmek kolay olmadığını

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

Not. Boru hattını kullanarak, kodu farklı yazabilirsiniz, ancak aynı şey anlamına gelecektir.

trick boruhattı operatör infix gösterimini (örneğin x |> f) kullanılarak iki parametre olmasıdır. x parametresi sağdaki bir işlevin son bağımsız değişkeni olarak iletilecektir (f). Herhangi F # işlevleriyle borulama kullanabilirsiniz:

let sinOne = 1.0 |> sin 

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

F # boruhattı operatörü ilgili önemli bir nokta da olmadığıdır herhangi bir özel dahili dilin özelliği.Bunun

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

Böylesine güçlü ve kullanışlı bir operatörün tanımının çok önemsiz olduğunu bana vuruyor. – Benjol