Komposisi fungsi Haskell (.) Dan fungsi aplikasi ($): penggunaan yang benar

129

Saya telah membaca Real World Haskell , dan saya mendekati akhir, tetapi masalah gaya telah mengganggu saya sehubungan dengan (.)dan ($)operator.

Ketika Anda menulis fungsi yang merupakan komposisi dari fungsi-fungsi lain, Anda menulisnya seperti:

f = g . h

Tetapi ketika Anda menerapkan sesuatu pada akhir fungsi-fungsi itu, saya menulisnya seperti ini:

k = a $ b $ c $ value

Tetapi buku itu akan menulis seperti ini:

k = a . b . c $ value

Sekarang, bagi saya mereka terlihat setara secara fungsional, mereka melakukan hal yang persis sama di mata saya. Namun, semakin saya melihat, semakin saya melihat orang-orang menulis fungsinya dengan cara yang dilakukan buku itu: menulis dengan yang (.)pertama dan kemudian hanya pada akhirnya menggunakan ($)untuk menambahkan nilai untuk mengevaluasi lot (tidak ada yang melakukannya dengan banyak komposisi dolar) .

Apakah ada alasan menggunakan cara buku yang jauh lebih baik daripada menggunakan semua ($)simbol? Atau ada praktik terbaik di sini yang tidak saya dapatkan? Atau itu berlebihan dan saya tidak perlu khawatir sama sekali?

Robert Massaioli
sumber
4
Perhatikan bahwa contoh kedua dapat dilakukan sebagaik = a $ b $ c value
Thomas Eding
1
Ya itu bisa, seperti yang disebutkan Zifre di bawah ini, tapi saya memutuskan untuk meninggalkannya di sana karena tidak membahayakan apa pun dan membuat komentarnya (dan sekarang Anda) masuk akal. Terima kasih. +1 :)
Robert Massaioli
2
Pendekatan umum lainnya adalah a . b $ c value, yang saya tidak suka sebanyak contoh ketiga tetapi menyimpan beberapa karakter.
John L

Jawaban:

153

Saya kira saya bisa menjawab ini dari otoritas.

Apakah ada alasan menggunakan cara buku yang jauh lebih baik daripada menggunakan semua simbol ($)?

Tidak ada alasan khusus. Bryan dan saya sama-sama lebih suka mengurangi kebisingan jalur. .lebih tenang dari $. Akibatnya, buku tersebut menggunakan f . g . h $ xsintaksis.

Don Stewart
sumber
3
Yah, saya tidak bisa berharap untuk jawaban yang lebih baik daripada yang ini; dari salah satu penulis sendiri. :) Dan itu masuk akal, memang terlihat jauh lebih tenang di halaman saat saya membaca. Menandai ini sebagai jawaban karena langsung menjawab pertanyaan. Terima kasih atas tanggapannya; dan, ternyata, buku itu.
Robert Massaioli
38
Bukan untuk tidak setuju dengan penulis, tapi saya pikir ada alasan lain yang lebih menonjol dalam model mental menciptakan sesuatu daripada menggunakannya . Pengguna Haskell cenderung ingin menganggapnya f.g.hsebagai kreasi cerdas baru f(g(h())). Sekarang mereka memanggil fungsi baru, meskipun anonim, yang mereka buat alih-alih hanya membuat kamus besar panggilan fungsi prefabbed seperti pengguna PHP.
Evan Carroll
1
Itu pernyataan yang menarik: 'kurangi noise garis' dan 'lebih tenang dari'. Saya tidak pernah berpikir tentang bahasa pemrograman dalam terminologi ini, tetapi itu masuk akal.
Rabarberski
53

Mereka memang setara: Ingat bahwa $operator pada dasarnya tidak melakukan apa pun. f $ xmengevaluasi ke f x. Tujuannya $adalah perilaku fixity: hak-asosiatif dan prioritas minimal. Menghapus $dan menggunakan tanda kurung untuk pengelompokan alih-alih prioritas infiks, potongan kode terlihat seperti ini:

k = a (b (c (value)))

dan

k = (a . b . c) value

Alasan untuk lebih memilih .versi daripada $versi adalah alasan yang sama untuk lebih memilih keduanya daripada versi yang sangat kurung di atas: daya tarik estetika.

Meskipun, beberapa mungkin bertanya-tanya apakah menggunakan operator infiks bukan tanda kurung didasarkan pada beberapa dorongan bawah sadar untuk menghindari kemungkinan kemiripan dengan Lisp (hanya bercanda ... saya pikir?).

CA McCann
sumber
38

Saya menambahkan bahwa f . g $ x, f . gadalah unit sintaksis yang bermakna.

Sementara itu, di f $ g $ x, f $ gbukan unit yang berarti. Sebuah rantai $ini bisa dibilang lebih penting - pertama mendapatkan hasil gdari x, kemudian lakukan fke sana, kemudian lakukan fooke sana, kemudian dll

Sementara itu sebuah rantai .bisa dikatakan lebih deklaratif, dan dalam beberapa hal lebih dekat dengan pandangan sentris aliran data - menyusun serangkaian fungsi, dan akhirnya menerapkannya pada sesuatu.

sclv
sumber
2
Saya belajar Haskell (belum memberi kode apa pun yang berarti) tetapi saya suka menganggap $ sebagai semacam operator "pipa". Sangat mirip terminal | pipa (kecuali data mengalir dari kanan ke kiri), tetapi seperti proses terminal setiap unit secara eksplisit independen.
LostSalad
1
The $Operator tampaknya berperilaku sama dengan <|operator dalam F #. Saya percaya keduanya didefinisikan sama, pada kenyataannya - di F #, (<|) a b = a bdan di Haskell a $ b = a b, yang pada dasarnya setara.
Tom Galvin
@ Quackmatic Cukup yakin itu ada (<|) b a = a bdi F #, karena ini digunakan seperti [1; 2; 3; 4; 5] <| List.map ((+) 1), jika ingatanku.
BalinKingOfMoria Reinstate CMs
@ BalinKingOfMoria <|Operator meneruskan nilai ke fungsi, alih-alih meneruskan fungsi ke nilai - contoh kode Anda akan bekerja dengan |>operator, sebagai gantinya.
Tom Galvin
@ Quackmatic Oh. Tidak menyadari ada beberapa versi (saya belum menggunakan F # sangat banyak).
BalinKingOfMoria Reinstate CMs
18

Bagi saya, saya pikir jawabannya adalah (a) kerapian, seperti kata Don ; dan (b) Saya menemukan bahwa ketika saya mengedit kode, fungsi saya mungkin berakhir dengan gaya point-free, dan yang harus saya lakukan adalah menghapus yang terakhir $alih-alih kembali dan mengubah segalanya. Poin kecil, tentu saja, tapi keramahtamahan.

Antal Spector-Zabusky
sumber
Ya itu alasan yang bagus untuk menulisnya seperti itu, jika Anda ingin mengakhiri komposisi fungsi maka itu lebih cepat. :) Yay untuk menghemat penekanan tombol, tetapi yang lebih penting waktu. +1
Robert Massaioli
13

Ada diskusi menarik tentang pertanyaan ini di utas kafe haskell ini . Rupanya ada sudut pandang minoritas yang memegang bahwa associativity tepat $adalah "sekadar salah" , dan memilih f . g . h $ xlebih f $ g $ h $ xadalah salah satu cara sisi-melangkah masalah ini.

Travis Brown
sumber
Hei, Anda menemukan seluruh diskusi tentang masalah ini. Itu luar biasa, saya sedang membaca sekarang. +1
Robert Massaioli
2
Argumen serupa di sini: ghc.haskell.org/trac/haskell-prime/wiki/…
enrique
Catatan yang $!juga memiliki "benar salah" asosiasi kanan - Mengapa $! Operator asosiatif? .
imz - Ivan Zakharyaschev
3

Ini hanya masalah gaya. Namun, cara buku itu membuat saya lebih masuk akal. Ini menyusun semua fungsi, dan kemudian menerapkannya pada nilai.

Metode Anda hanya terlihat aneh, dan yang terakhir $tidak perlu.

Namun, itu tidak masalah. Di Haskell, biasanya ada banyak, banyak, cara yang benar untuk melakukan hal yang sama.

Zifre
sumber
3
Saya tidak menyadari bahwa $ terakhir itu tidak perlu tetapi saya seharusnya. Terima kasih dan saya akan meninggalkannya di sana sehingga orang tahu apa artinya komentar ini.
Robert Massaioli
0

Saya menyadari ini adalah pertanyaan yang sangat lama, tetapi saya pikir ada alasan lain untuk ini yang belum disebutkan.

Jika Anda mendeklarasikan fungsi bebas titik baru f . g . h, nilai yang Anda berikan akan secara otomatis diterapkan. Namun, jika Anda menulis f $ g $ h, itu tidak akan berhasil.

Saya pikir alasan penulis lebih suka metode komposisi adalah karena mengarah pada praktik yang baik untuk membangun fungsi.

hackeryarn
sumber