Apakah suatu fungsi segera tidak murni jika mengambil fungsi sebagai parameter?

17

Karena kemurnian parameter input tidak diketahui hingga runtime, apakah fungsi segera dianggap tidak murni jika mengambil fungsi sebagai parameter input?

Terkait: jika suatu fungsi menerapkan fungsi murni yang didefinisikan di luar fungsi, tetapi tidak dimasukkan sebagai parameter, apakah masih murni jika memenuhi kriteria tidak memiliki efek samping dan output hanya bergantung pada input?

Untuk konteks, saya sedang menulis kode fungsional dalam JavaScript.

Dancrumb
sumber
Sebagai contoh counter sepele, pertimbangkan:foo = function(function bar){ print(bar.toString()) }
David mengatakan Reinstate Monica
1
@ DavidGrinberg Itu bukan contoh balasan, saya pikir, dan sebenarnya menyoroti masalah yang lebih besar; jika Anda memiliki fungsi yang dapat ditimpa, dan tidak dapat menjamin bahwa implementasi bebas efek samping, maka Anda tidak dapat menjamin bahwa sebagian besar fungsi yang mengambil objek dan memanggil metode mereka murni. Mungkin toString () bar menghapus beberapa file dari disk?
Joshua Taylor
3
@ David Grinberg Tapi, saya pikir Anda berpikir ke arah yang baik. foo = function(function bar) { return 3; } adalah murni, dan mengambil fungsi sebagai argumen.
Joshua Taylor
@ JoshuaTaylor Fair point, saya tidak memikirkan itu. Tapi pada dasarnya Anda sudah memecahkan masalah. Sebagai perbaikan alternatif, panggil saja 'root' toString()(yaitu yang Anda akan temukan di Obyek Java).
David mengatakan Reinstate Monica

Jawaban:

22

Selama semua nilai yang digunakan dalam fungsi ditentukan hanya oleh parameternya, itu adalah fungsi murni.

Faset yang outputnya sama setiap kali untuk input yang sama dikendalikan oleh apakah parameternya murni. Jika Anda menganggap parameter (seperti argumen fungsi) juga murni, maka itu murni.

Dalam bahasa seperti Javascript di mana kemurnian tidak ditegakkan, ini berarti bahwa dimungkinkan untuk membuat fungsi yang murni memiliki perilaku tidak murni dengan menjalankan fungsi tidak murni yang dilewatkan sebagai parameter.

Ini secara efektif berarti bahwa untuk bahasa yang tidak menegakkan kemurnian (yaitu hampir semua), tidak mungkin untuk mendefinisikan fungsi murni yang memanggil fungsi yang dilewatkan sebagai argumen. Masih berguna untuk menulisnya semurni mungkin, dan untuk menanggapinya sebagai fungsi murni, tetapi Anda harus berhati-hati karena asumsi bahwa itu murni akan rusak jika Anda memberikan argumen yang salah.

Dalam pengalaman saya dalam praktik, ini biasanya bukan masalah besar - saya merasa jarang memiliki fungsi yang tidak murni digunakan sebagai argumen fungsi untuk fungsi murni.

Daenyth
sumber
Mengenai pernyataan Anda bahwa "Selama semua nilai yang digunakan dalam fungsi ditentukan hanya oleh parameternya, itu adalah fungsi murni". Apa yang terjadi dalam kasus konstanta? Jika saya memiliki fungsi areaOfCircle r => Math.Pi * r * r, apakah akan areaOfCirclenon-murni karena tidak hanya menggunakan parameter?
David Arno
2
@ DavidArno Itu poin yang adil. Menurut transparansi referensial, merujuk pada nilai luar yang statis tidak akan berbeda dengan membuatnya dengan hardcode, jadi itu akan tetap murni.
Daenyth
1
"Ini berarti bahwa dimungkinkan untuk membuat fungsi murni memiliki perilaku tidak murni" - menurut definisi, fungsi murni tidak dapat memiliki perilaku tidak murni. Anda membuat kesalahan dengan berpikir f(f2)bahwa fungsi yang dipanggil f2tidak bergantung secara transitif pada apa pun yang f2diandalkan. Fungsi yang mungkin menjalankan fungsi sewenang-wenang tidak murni.
user2357112 mendukung Monica
2
@ Ketidaksamaan: Lebih baik, tetapi masih mengasumsikan bahwa fungsi tersebut harus memanggil fungsi yang lewat. Mungkin sesuatu seperti itu function compose(f, g) {return function h(x) {return f(g(x));};}, yang murni meskipun mengambil fungsi sebagai argumen.
user2357112 mendukung Monica
1
"Saya merasa jarang memiliki fungsi tidak murni digunakan sebagai argumen fungsi untuk fungsi murni." - bukan bahasa fungsional, tetapi fungsi pustaka C ++ tertentu memiliki peringatan khusus yang mendasari argumen harus (sebagian perkiraan) murni. Jadi di satu sisi ini berarti itu tidak hanya langka, itu tidak pernah terjadi secara sah. Tetapi dalam arti lain kenyataan bahwa mereka harus melarangnya adalah karena orang kadang-kadang ingin melakukannya. Misalnya mereka ingin memberikan findrutin predikat tidak murni yang mengembalikan "benar" untuk item pencocokan ketiga yang dijumpainya, atau omong kosong semacam itu.
Steve Jessop
19

Karena kemurnian parameter input tidak diketahui hingga runtime, apakah fungsi segera dianggap tidak murni jika mengambil fungsi sebagai parameter input?

Tidak. Contoh balik:

function pure(other_function) {
    return 1;
}

Tidak masalah apakah other_functionitu fungsi murni, fungsi tidak murni, atau tidak fungsi sama sekali. The purefungsi murni.

Contoh tandingan lainnya:

function identity(x) {
    return x;
}

Fungsi ini murni, meskipun xmerupakan fungsi yang tidak murni. identity(impure_function)akan selalu kembali impure_function, tidak peduli berapa kali Anda mengulangi panggilan. Tidak masalah apakah identity(impure_function)()selalu mengembalikan hal yang sama; nilai pengembalian nilai fungsi tidak mempengaruhi kemurniannya.


Secara umum, jika suatu fungsi mungkin memanggil fungsi itu disahkan sebagai argumen, itu tidak murni. Misalnya, suatu fungsi function call(f) {f();}tidak murni, karena meskipun tidak menyebutkan keadaan global atau yang bisa berubah, fmungkin sesuatu seperti alertitu yang menyebabkan efek samping yang terlihat.

Jika suatu fungsi mengambil fungsi sebagai argumen, tetapi tidak memanggilnya atau menyebabkannya dipanggil, maka itu bisa murni. Mungkin masih tidak murni jika melakukan beberapa hal tidak murni lainnya. Misalnya, function f(ignored_function) {alert('This isn't pure.');}tidak murni, meskipun tidak pernah memanggil ignored_function.

user2357112 mendukung Monica
sumber
4
Respons ini tampaknya terlalu berlebihan. Kita dapat menyimpulkan dari pertanyaan bahwa kekhawatirannya adalah parameter fungsi yang dipanggil. Keberadaan fungsi yang dapat / tidak mengambil fungsi lain sebagai parameter tanpa memohonnya tidak mempengaruhi pertanyaan ini.
walpen
13
@walpen: Pertanyaannya tidak menyebutkan memohon argumen. Tidak ada alasan untuk menganggap si penanya bahkan menyadari suatu fungsi mungkin mengambil fungsi lain sebagai input tanpa memintanya. Penting untuk menunjukkan asumsi tersembunyi seperti ini, daripada hanya berasumsi bahwa Anda seharusnya menganggapnya.
user2357112 mendukung Monica
12

Karena kemurnian parameter input tidak diketahui hingga runtime, apakah fungsi segera dianggap tidak murni jika mengambil fungsi sebagai parameter input?

Secara teknis, ya, kecuali ada beberapa cara dalam bahasa Anda untuk menjamin bahwa fungsi input juga murni.

jika suatu fungsi menerapkan fungsi murni yang didefinisikan di luar fungsi, tetapi tidak dimasukkan sebagai parameter, apakah masih murni jika memenuhi kriteria tidak memiliki efek samping dan output hanya bergantung pada input?

Iya. Jadi mari kita fokus pada apa yang penting di sini. Memanggil fungsi murni atau tidak tidak berguna. Fungsi murni bermanfaat karena menghasilkan output yang sama untuk input apa pun dan tidak bergantung pada status atau memiliki efek samping adalah serangkaian properti yang sangat berguna. Ini berarti bahwa setelah fungsi Anda dijalankan, Anda dapat "mengingat" jawaban untuk input itu dan itu akan selalu benar. Anda juga tidak perlu menjalankan fungsi lagi untuk menghasilkan efek samping. Dan Anda dapat menjalankan fungsi itu secara paralel (atau rusak) dengan fungsi lain dan tahu bahwa mereka tidak akan memiliki interaksi tersembunyi yang berperilaku buruk.

Properti yang bermanfaat itu masih berlaku jika fungsi menggunakan fungsi read-only murni lainnya untuk melakukan tugasnya, terlepas dari bagaimana referensi itu.

Telastyn
sumber
5

Seperti yang dikatakan Telastyn: Secara teknis, ya, kecuali ada beberapa cara dalam bahasa Anda untuk menjamin bahwa fungsi input juga murni.

Itu bukan hipotesis, memang ada cara yang baik untuk menjamin ini. Setidaknya dalam bahasa yang sangat diketik.

Seperti fungsi ~ murni yang akan Anda tulis dalam JavaScript

function foo(f) {
   return f(1) + 2;
}

dapat diterjemahkan langsung ke Haskell:

foo :: (Int -> Int) -> Int
foo f = f 1 + 2

Sekarang, di JavaScript Anda bisa melakukan hal-hal jahat

js> foo (function(x) {console.log("muharhar"); return 0})
muharhar
2

Ini tidak mungkin di Haskell . Alasannya, sesuatu seperti efek samping console.log()harus selalu memiliki tipe hasil IO something, tidak hanya somethingsendirian.

GHCi> foo (\x -> print "muarhar" >> return 0)

<interactive>:7:12:
    Couldn't match expected type ‘Int’ with actual type ‘IO b0’
    In the expression: print "muarhar" >> return 0
    In the first argument of ‘foo’, namely
      ‘(\ x -> print "muarhar" >> return 0)’
    In the expression: foo (\ x -> print "muarhar" >> return 0)

Untuk ekspresi ini untuk mengetik centang, kita perlu memberikan footanda tangan jenis

foo :: (Int -> IO Int) -> Int

Tapi ternyata saya tidak bisa mengimplementasikannya lagi: karena fungsi argumen ada IOdi hasilnya, saya tidak bisa menggunakannya di dalamnya foo.

<interactive>:8:44:
    Couldn't match expected type ‘Int’ with actual type ‘IO Int’
    In the first argument of ‘(+)’, namely ‘f 1’
    In the expression: f 1 + 2

Satu-satunya cara saya bisa menggunakan IOtindakan fooadalah jika hasil foomemiliki tipe IO Intitu sendiri:

foo :: (Int -> IO Int) -> IO Int
foo f = do
   f1 <- f 1
   return (f1 + 2)

Tetapi pada titik ini jelas dari tanda tangan foobahwa itu juga bukan fungsi murni.

leftaroundabout
sumber
1
Sebelum Anda mengatakan "tidak mungkin", lihatlah unsafeIO:-)
Bergi
2
@Bergi: itu sebenarnya bukan bagian dari Haskell, tetapi dari antarmuka fungsi asing: untuk memungkinkan menyatakan bahwa fungsi yang didefinisikan dalam beberapa bahasa lain adalah murni, yang kompiler Haskell jelas tidak dapat disimpulkan dari jenis tanda tangan karena bahasa lain umumnya tidak memiliki hal seperti itu IO. Kebetulan, itu juga dapat digunakan untuk menyebabkan kekacauan dengan menyembunyikan efek samping dalam fungsi "murni", tapi itu benar - benar tidak aman di Haskell karena tidak ada cara yang dapat diandalkan untuk menentukan urutan evaluasi fungsi murni.
leftaroundabout
Ya itu benar. Namun, saya pikir saya telah melihatnya digunakan untuk "menyembunyikan" efek samping yang menguntungkan dalam fungsi "murni" juga, di mana keamanan dari pendekatan tersebut harus ditetapkan sebelumnya.
Bergi
@Bergi Anda sebaiknya tidak menggunakan unsafeIO; itu adalah jalan keluar penyelamatan terakhir yang menghindari jaminan tipe sistem, dan karenanya milik Anda bukanlah poin yang baik.
Andres F.
0

Tidak, bukan itu.

Jika fungsi yang diteruskan tidak murni DAN fungsi Anda memanggil fungsi yang lewat maka fungsi Anda akan dianggap tidak murni.

Relasi murni / tidak murni agak mirip sinkronisasi / async di JS. Anda dapat dengan bebas menggunakan kode murni dari yang tidak murni, tetapi tidak sebaliknya.

Bobby Marinoff
sumber
Jawaban ini tidak menambahkan apa pun yang belum dijelaskan dalam yang ini ... Silakan tinjau jawaban sebelumnya sebelum menyatakan kembali :)
Andres F.
Bagaimana dengan analogi sinkronisasi / async?
Bobby Marinoff