Haskell bileşimi (.) - F # 'ın ileri boru operatörü (|>)


100

F # 'da, boru ileri operatörünün |>kullanımı oldukça yaygındır. Ancak Haskell'de şimdiye kadar yalnızca işlev bileşiminin (.)kullanıldığını gördüm . İlişkili olduklarını anlıyorum , ancak Haskell'de boru ilerletmenin kullanılmamasının bir dil nedeni var mı yoksa başka bir şey mi?


2
lihanseys cevabı& Haskell'in olduğunu belirtir |>. Bu ipin derinliklerine gömüldü ve keşfetmem birkaç günümü aldı. Kodunuzu takip etmek için doğal olarak soldan sağa okuduğunuz için çok kullanıyorum.
itmuckel

Yanıtlar:


61

Biraz spekülatif oluyorum ...

Kültür : Bence |>F # "kültürü" için önemli bir operatör ve belki de .Haskell için benzer şekilde . F # bir işlev oluşturma işlecine sahiptir, <<ancak F # topluluğunun Haskell topluluğundan daha az puan içermeyen stili kullanma eğiliminde olduğunu düşünüyorum .

Dil farklılıkları : Her iki dil hakkında karşılaştırmak için yeterince bilgim yok, ama belki de izin bağlamaları genelleme kuralları, bunu etkileyecek kadar yeterince farklı. Örneğin, F # dilinde bazen yazdığımı biliyorum

let f = exp

derlenmeyecek ve açık bir eta-dönüşümüne ihtiyacınız var:

let f x = (exp) x   // or x |> exp

derlemek için. Bu aynı zamanda insanları noktasız / kompozisyon stilinden uzaklaştırır ve ardışık düzen stiline doğru yönlendirir. Ayrıca, F # tipi çıkarım bazen ardışık düzen gerektirir, böylece solda bilinen bir tür görünür ( buraya bakın ).

(Şahsen, noktasız stili okunamaz buluyorum, ancak sanırım her yeni / farklı şey, siz alışana kadar okunamaz görünüyor.)

Her ikisinin de her iki dilde de potansiyel olarak geçerli olduğunu düşünüyorum ve tarih / kültür / kaza her bir topluluğun neden farklı bir "çekiciye" yerleştiğini tanımlayabilir.


7
Kültürel farklılıklara katılıyorum. Geleneksel Haskell kullanır .ve $böylece insanlar bunları kullanmaya devam eder.
Amok

9
Ücretsiz puan bazen anlamlı olmaktan çok okunabilir, bazen daha azdır. Lambda'nın işleri karıştırmasını önlemek için, bunu genellikle harita ve filtre gibi işlevler için argümanda kullanırım. Bazen bunu üst düzey işlevlerde de kullanıyorum, ancak daha az sıklıkla ve yalnızca basit bir şey olduğunda.
Paul Johnson

2
F # söz konusu olduğunda (sizin ve Ganesh'in bahsettiği nedenlerden dolayı) bu konuda pek fazla seçenek olmaması anlamında bunda fazla kültür görmüyorum. Bu nedenle, her ikisinin de Haskell'de geçerli olduğunu söyleyebilirim, ancak F # kesinlikle boru hattı operatörünü kullanmak için çok daha donanımlıdır.
Kurt Schelfthout

2
evet, soldan sağa okuma kültürü :) matematik bile bu şekilde öğretilmeli ...
nicolas

1
@nicolas soldan sağa keyfi bir seçimdir. Sağdan sola alışabilirsin.
Martin Capodici

86

F # ' (|>)de soldan sağa yazım denetimi nedeniyle önemlidir. Örneğin:

List.map (fun x -> x.Value) xs

genellikle typecheck yapmaz, çünkü türü bilinse bile , lambda xsargümanının türü xtypechecker tarafından görüldüğü anda bilinmez, bu yüzden nasıl çözüleceğini bilmez x.Value.

Tersine

xs |> List.map (fun x -> x.Value)

iyi çalışacak, çünkü türü xsbilinme türüne yol açacaktır x.

Gibi yapılarda yer alan ad çözümlemesi nedeniyle soldan sağa yazım denetimi gereklidir x.Value. Simon Peyton Jones, Haskell'e benzer türde bir ad çözümlemesi eklemek için bir öneri yazdı , ancak bunun yerine bir türün belirli bir işlemi destekleyip desteklemediğini izlemek için yerel kısıtlamaların kullanılmasını öneriyor. Böylece ilk örnekte, xbir Valuemülke ihtiyaç duyan gereksinim görülene kadar ileri taşınacak xsve bu gereksinim çözülebilecektir. Yine de bu, tip sistemini karmaşıklaştırır.


1
İlginç olan, Haskell'de sağdan sola aynı veri yönüne sahip (.) 'Ye benzer (<|) operatörünün olmasıdır. Ancak bunun için tür çözünürlüğü nasıl çalışacak?
The_Ghost

7
(<|) aslında Haskell'in ($) değerine benzer. Soldan sağa yazım denetimi yalnızca .Value gibi şeyleri çözmek için gereklidir, bu nedenle (<|) diğer senaryolarda veya açık tür ek açıklamaları kullanıyorsanız iyi çalışır.
GS - Monica'dan özür dile

44

Daha fazla spekülasyon, bu sefer ağırlıklı olarak Haskell tarafından ...

($)ters çevrilir ve noktasız (|>)kod yazamadığınızda kullanımı oldukça yaygındır. Yani (|>)Haskell'de kullanılmamasının ana sebebi , yerinin çoktan alınmış olmasıdır ($).

Ayrıca, biraz F # deneyiminden bahsedersek, (|>)F # kodunda çok popüler olduğunu düşünüyorum çünkü OO'nun Subject.Verb(Object)yapısına benziyor . F #, sorunsuz bir işlevsel / OO entegrasyonunu hedeflediğinden, Subject |> Verb Objectyeni işlevsel programcılar için oldukça yumuşak bir geçiş.

Şahsen ben de soldan sağa düşünmeyi seviyorum, bu yüzden (|>)Haskell'de kullanıyorum, ancak diğer pek çok insanın yaptığını sanmıyorum.


Merhaba Nathan, Haskell platformunun herhangi bir yerinde "flip ($)" önceden tanımlanmış mı? "(|>)" Adı, başka bir anlamla Data.Sequence içinde zaten tanımlanmıştır. Henüz tanımlanmamışsa, ona ne diyorsunuz? "($>) = Flip ($)" ile gitmeyi düşünüyorum
mattbh

2
@mattbh: Hoogle ile bulabileceğimden değil. Bilmiyordum Data.Sequence.|>ama $>oradaki çatışmalardan kaçınmak için makul görünüyor. Dürüst olmak gerekirse, yalnızca çok sayıda iyi görünümlü operatör var, bu yüzden |>her ikisi için de kullanır ve çatışmaları duruma göre yönetirim. (Ayrıca ben sadece takma için cazip olacağını Data.Sequence.|>olarak snoc)
Nathan Shively-Sanders

2
($)ve (|>)uygulama kompozisyon değildir. İki (senin (soru notlar gibi) ilgili ama aynı değillerdir fcolan (Control.Arrow.>>>)fonksiyonlar için).
Nathan Shively-Sanders

11
Pratikte, F # 'ler |>aslında bana |her şeyden çok UNIX'i hatırlatıyor .
Kevin Cantu

3
|>F # uygulamasının diğer bir avantajı, Visual Studio'da IntelliSense için güzel özelliklere sahip olmasıdır. Tip |>ve ne benzer soldaki değere uygulanabilir fonksiyonları, bir listesini almak zaman yazarak .bir nesne sonra.
Kristopher Johnson

32

Sanırım bir şeyleri karıştırıyoruz. Haskell's ( .), F # 's ( >>) ile eşdeğerdir . |>Sadece tersine çevrilmiş fonksiyon uygulaması olan ve Haskell'in ( $) gibi olan F # 's ( ) ile karıştırılmamalıdır - tersine çevrilmiştir:

let (>>) f g x = g (f x)
let (|>) x f = f x

Haskell programcılarının $sıklıkla kullandığına inanıyorum . Belki de F # programcılarının kullandığı sıklıkta değil |>. Öte yandan, bazı F # adamları >>saçma derecede kullanır: http://blogs.msdn.com/b/ashleyf/archive/2011/04/21/programming-is-pointless.aspx


2
Eğer Haskell'ın gibi söylersem olarak $: - operatör ters de kolayca olarak tanımlanan olabilir a |> b = flip ($)o zaman yapabilirsiniz eg boru hattı 'nın F # eşdeğer hale geldiği[1..10] |> map f
vis

8
Bence ( .), ( ) ile aynı <<, oysa ( >>) ters bileşimdir. Bu ( >> ) : ('T1 -> 'T2) -> ('T2 -> 'T3) -> 'T1 -> 'T3vs( << ) : ('T2 -> 'T3) -> ('T1 -> 'T2) -> 'T1 -> 'T3
Dobes Vandermeer

-1 "saçma bir dereceye kadar kullanmak" için. (Ben yapmadım ama sen benim fikrimi anladın). F # 'da F "işlevsel" içindir, bu nedenle işlev bileşimi meşrudur.
Florian F

1
Kesinlikle işlev bileşiminin yasal olduğuna katılıyorum. "Bazı F # adamları" derken kendimi kastediyorum! Bu benim kendi blogum. : P
AshleyF

.Eşit olduğunu sanmıyorum >>. F # <<değerinde olup olmadığını bilmiyorum ama bu eşdeğer olacaktır (Elm'deki gibi).
Matt Joiner

28

F # kullanmak istiyorsanız 's |>sonra Haskell Data.Function olan &(çünkü operatör base 4.8.0.0).


Haskell'in bunu seçmesi için bir neden &var |>mı? Sanki |>çok daha sezgisel olduğunu hissediyorum ve aynı zamanda bana Unix boru operatörünü hatırlatıyor.
yeshengm

@yeshengm &Çok sezgisel buluyorum . Kod İngilizce'de &"ve" olarak telaffuz edilerek neredeyse doğru okunur . Örneğin: 5 & factorial & show"5'i al ve sonra faktöriyelini al ve sonra ona göster" şeklinde yüksek sesle okur.
Marcel Besixdouze

16

Haskell'de soldan sağa kompozisyon

Haskell'de bazı insanlar soldan sağa (mesaj geçirme) stilini de kullanır. Örneğin Hackage'daki mps kitaplığına bakın. Bir örnek:

euler_1 = ( [3,6..999] ++ [5,10..999] ).unique.sum

Bu tarzın bazı durumlarda güzel göründüğünü düşünüyorum ama okumak daha zor (kütüphane ve tüm operatörlerini bilmek gerekiyor, yeniden tanımlanmış olanlar (.)da rahatsız edicidir).

Temel paketin parçası olan Control.Category'da soldan sağa ve sağdan sola kompozisyon operatörleri de vardır . Karşılaştır >>>ve <<<sırasıyla:

ghci> :m + Control.Category
ghci> let f = (+2) ; g = (*3) in map ($1) [f >>> g, f <<< g]
[9,5]

Bazen soldan sağa kompozisyonu tercih etmenin iyi bir nedeni vardır: değerlendirme sırası okuma sırasını takip eder.


Güzel, yani (>>>) büyük ölçüde (|>) ile eşittir?
Khanzor

@Khanzor Tam olarak değil. (|>) bir bağımsız değişken uygular, (>>>) çoğunlukla işlev bileşimidir (veya benzer şeylerdir). Öyleyse sanırım bazı sabitlik farkı var (kontrol etmedim).
sastanin

15

Bunun için >>>kullanıldığını gördüm flip (.)ve bunu sık sık kullanıyorum, özellikle soldan sağa en iyi anlaşılan uzun zincirler için.

>>> aslında Control.Arrow'dan ve işlevlerden daha fazlası üzerinde çalışıyor.


>>>tanımlanmıştır Control.Category.
Steven Shaw

13

Tarz ve kültürün yanı sıra, bu, dil tasarımını saf veya saf olmayan kod için optimize etmeye indirgiyor.

|>O ağırlıklı-saf olmayan kodunun yer aldığı iki sınırlamaları nasıl gizlediği büyük nedeni operatör F # yaygındır:

  • Yapısal alt türler olmadan soldan sağa tür çıkarımı.
  • Değer kısıtlaması.

Önceki sınırlamanın OCaml'de bulunmadığına dikkat edin, çünkü alt tipleme nominal yerine yapısaldır, bu nedenle yapısal tip, tip çıkarımı ilerledikçe birleştirme yoluyla kolayca iyileştirilebilir.

Haskell, bu sınırlamaların kaldırılabileceği, ağırlıklı olarak saf koda odaklanmayı seçerek farklı bir ödünleşim yapıyor.


8

Haskell'de F # 'ın ileri boru operatörü ( |>) ile ( & ) arasında olması gerektiğini düşünüyorum .

// pipe operator example in haskell

factorial :: (Eq a, Num a) =>  a -> a
factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)
// terminal
ghic >> 5 & factorial & show

( &) Operatörünü beğenmezseniz, F # veya Elixir gibi özelleştirebilirsiniz:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 1 |>
ghci>> 5 |> factorial |> show

Neden infixl 1 |>? Data-Function (&) belgesine bakın

infixl = infix + sol çağrışım

infixr = infix + doğru ilişkilendirilebilirlik


(.)

( .) işlev bileşimi anlamına gelir. Matematikte (fg) (x) = f (g (x)) anlamına gelir .

foo = negate . (*3)
// ouput -3
ghci>> foo 1
// ouput -15
ghci>> foo 5

eşittir

// (1)
foo x = negate (x * 3) 

veya

// (2)
foo x = negate $ x * 3 

( $) operatörü ayrıca Data-Function ($) içinde tanımlanır .

( .) Hight Order Functionveya oluşturmak için kullanılır closure in js. Örneğe bakın:


// (1) use lamda expression to create a Hight Order Function
ghci> map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]  
[-5,-3,-6,-7,-3,-2,-19,-24]


// (2) use . operator to create a Hight Order Function
ghci> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]  
[-5,-3,-6,-7,-3,-2,-19,-24]

Vay canına, Daha az (kod) daha iyidir.


Karşılaştır |>ve.

ghci> 5 |> factorial |> show

// equals

ghci> (show . factorial) 5 

// equals

ghci> show . factorial $ 5 

Bu arasındaki farklıdır left —> rightve right —> left. ⊙﹏⊙ |||

İnsanlaştırma

|>ve &daha iyi.

Çünkü

ghci> sum (replicate 5 (max 6.7 8.9))

// equals

ghci> 8.9 & max 6.7 & replicate 5 & sum

// equals

ghci> 8.9 |> max 6.7 |> replicate 5 |> sum

// equals

ghci> (sum . replicate 5 . max 6.7) 8.9

// equals

ghci> sum . replicate 5 . max 6.7 $ 8.9

Nesne yönelimli dilde işlevsel programlama nasıl yapılır?

lütfen http://reactivex.io/ adresini ziyaret edin

Bilişim Destek :

  • Java: RxJava
  • JavaScript: RxJS
  • C #: Rx.NET
  • C # (Birlik): UniRx
  • Scala: RxScala
  • Clojure: RxClojure
  • C ++: RxCpp
  • Lua: RxLua
  • Yakut: Rx.rb
  • Python: RxPY
  • Git: RxGo
  • Harika: RxGroovy
  • JRuby: RxJRuby
  • Kotlin: RxKotlin
  • Swift: RxSwift
  • PHP: RxPHP
  • İksir: reaksif
  • Dart: RxDart

1

Bu, Haskell'i denemek için ilk günüm (Rust ve F # sonrasında) ve F # 's |> operatörünü tanımlayabildim:

(|>) :: a -> (a -> b) -> b
(|>) x f = f x
infixl 0 |>

ve işe yarıyor gibi görünüyor:

factorial x =
  case x of
    1 -> 1
    _ -> x * factorial (x-1)

main =     
    5 |> factorial |> print

Bahse girerim bir Haskell uzmanı size daha da iyi bir çözüm verebilir.


1
infix operatörlerini de tanımlayabilirsiniz :) x |> f = f x
Jamie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.