Apakah eta-equivalence untuk fungsi-fungsi yang kompatibel dengan operasi seq Haskell?


14

Lemma: Dengan asumsi kesetaraan eta kita memilikinya (\x -> ⊥) = ⊥ :: A -> B.

Bukti: ⊥ = (\x -> ⊥ x)dengan kesetaraan eta, dan (\x -> ⊥ x) = (\x -> ⊥)dengan pengurangan di bawah lambda.

Laporan Haskell 2010, bagian 6.2 menentukan seqfungsi dengan dua persamaan:

seq :: a -> b -> b
seq ⊥ b = ⊥
seq ab = b, jika a ≠ ⊥

Itu kemudian mengklaim "Sebagai konsekuensinya, ⊥ tidak sama dengan \ x -> ⊥, karena seq dapat digunakan untuk membedakannya."

Pertanyaan saya adalah, apakah itu benar-benar konsekuensi dari definisi seq?

Argumen implisit tampaknya yang seqtidak dapat diperhitungkan jika seq (\x -> ⊥) b = ⊥. Namun saya belum dapat membuktikan bahwa hal seperti seqitu tidak dapat dihitung. Bagi saya, sepertinya seqitu monoton, dan terus-menerus, yang menempatkannya dalam ranah komputabel.

Algoritme yang mengimplementasikan seperti seq mungkin bekerja dengan mencoba mencari beberapa xtempat f x ≠ ⊥dengan menyebutkan domain fdimulai dengan ⊥. Meskipun implementasi seperti itu, bahkan jika mungkin sama sekali, menjadi sangat berbulu ketika kita ingin membuat seqpolimorfik.

Apakah ada bukti bahwa tidak ada dihitung seqbahwa mengidentifikasi (\x -> ⊥)dengan ⊥ :: A -> B? Atau, apakah ada beberapa konstruksi seqyang tidak sesuai (\x -> ⊥)dengan ⊥ :: A -> B?

Jawaban:


6

Pertama, mari kita secara eksplisit tentang bagaimana seqmembedakan dari :λx.

bottom :: a
bottom = bottom

eta :: a -> b
eta x = bottom

-- This terminates
fortytwo = seq eta 42

-- This does not terminate
infinity = seq bottom 42

Oleh karena itu fakta eksperimental bahwa di Haskell dan dapat dibedakan secara operasional. Itu juga fakta, dan yang cukup jelas, yang dapat dihitung karena Haskell yang menghitungnya. Begitu banyak tentang Haskell. Anda bertanya tentang ungkapan yang sangat khusus dari dokumentasi Haskell. Saya membacanya dengan mengatakan bahwa seharusnya memenuhi dua persamaan yang diberikan, tetapi kedua persamaan itu tidak cukup untuk definisi . Inilah alasannya: Saya dapat memberi Anda dua model (cukup diketik) -calculus yang dapat dihitung dan memenuhi persamaan yang diberikan, tetapi di salah satu model danλx.seqseqseqλseqλx. setuju, sementara yang lain tidak.

Dalam model domain-teori sederhana di mana -expresi ditafsirkan dalam domain fungsi kontinu kita memiliki , tentu saja. Ambil domain Scott yang efektif atau semacamnya untuk membuat semuanya dapat dihitung. Mudah untuk didefinisikan dalam model seperti itu.λ[DE]=λx.seq

Kita juga dapat memiliki model -calculus yang membedakan dan , dan tentu saja -rule tidak dapat menampung. Sebagai contoh, kita dapat melakukan ini dengan menginterpretasikan fungsi-fungsi dalam domain , yaitu domain fungsi ruang dengan tambahan bottom terpasang. Sekarang adalah, well, bagian bawah , sementara adalah elemen tepat di atasnya. Mereka tidak dapat dibedakan oleh aplikasi karena keduanya mengevaluasi ke , tidak peduli apa pun yang Anda terapkan (keduanya secara ekstensi sama ). Tapi kami punyaλseqλx.η[DE][DE]λx.seq sebagai peta antara domain dan itu juga membedakan bawah dari semua elemen lainnya.


1
Ini adalah fakta eksperimental yang ada di GHC dan / atau Hugs ⊥ dan λx.⊥. Untungnya, Haskell tidak didefinisikan oleh implementasi. Pertanyaan saya menunjukkan bahwa Haskell kurang spesifik dalam hal seq.
Russell O'Connor

Bisakah Anda memberikan referensi ke apa yang Anda maksud dengan "domain Scott efektif" Agaknya itu tidak menyiratkan bahwa urutan parsial dapat ditentukan. Juga, STLC bukan polimorfik, tetapi Haskell. Biasanya Haskell ditafsirkan dalam Sistem F atau salah satu turunannya. Bagaimana ini memengaruhi argumen Anda?
Russell O'Connor

Bagian 1.1.4 dari Ph.D. disertasi andrej.com/thesis/thesis.pdf memiliki definisi singkat tentang domain Scott yang efektif, dan ini sebenarnya adalah hit Google pertama yang tersedia secara bebas.
Andrej Bauer

2
Jika Anda menulis bukti untuk saya, Anda akan mendapatkan implementasi Haskell 98 di mana aturan eta berlaku untuk memungkinkan (foldr (\ ab -> fab) z xs) untuk dioptimalkan menjadi (foldr fz xs) menyebabkan peningkatan kinerja asimptotik dari O (n ^ 2) hingga O (n) (lihat ghc.haskell.org/trac/ghc/ticket/7436 ). Lebih menariknya akan memungkinkan NewTypeWrapper di (NewTypeWrapper. F) dioptimalkan tanpa memaksa f untuk diperluas eta dan mencegah beberapa hukuman kinerja asimptotik yang saat ini dikenakan oleh NewType di GHC (dalam penggunaan foldr misalnya).
Russell O'Connor

1
Sebenarnya, Anda harus memastikan bahwa kompiler Anda selalu mengimplementasikan as . Artinya, Anda mungkin tergoda untuk tidak selalu berkontraksi dan pada prinsipnya λ x . dan akan "kadang-kadang dapat dibedakan", situasi yang sangat berbahaya. Untuk memastikan hal ini tidak terjadi, Anda perlu mengimplementasikannya dengan cerdas yang melibatkan pemijahan tak terhingga banyaknya setiap proses yang masing-masing menerapkan fungsi Anda ke elemen dasar. Jika ada proses yang berakhir, maka dapat dilanjutkan. Akan menarik untuk melihat apakah kita bisa melakukan ini secara berurutan. Hmm. λx.λx.seqseq
Andrej Bauer

2

Perhatikan bahwa spesifikasi seqyang Anda kutip bukan definisi. Mengutip laporan Haskell "Fungsi seq didefinisikan oleh persamaan : [dan kemudian persamaan yang Anda berikan]".

Argumen yang disarankan tampaknya seq akan tidak dapat dihitung jika seq (\ x -> ⊥) b = ⊥.

Perilaku seperti itu akan melanggar spesifikasi seq.

Yang penting, karena seqbersifat polimorfik, seqtidak dapat didefinisikan dalam hal dekonstruksi (proyeksi / pencocokan pola, dll.) Pada salah satu dari dua parameter.

Apakah ada bukti bahwa tidak ada seq komputer yang mengidentifikasi (\ x -> ⊥) dengan ⊥ :: A -> B?

Jika seq' (\x -> ⊥) b, orang mungkin berpikir kita bisa menerapkan parameter pertama (yang merupakan fungsi) ke beberapa nilai dan kemudian. Keluar. Tetapi, seqtidak pernah dapat mengidentifikasi parameter pertama dengan nilai fungsi (bahkan jika itu menjadi satu untuk beberapa penggunaan seq) karena jenis polimorfik parametriknya. Parametrisitas berarti kita tidak tahu apa pun tentang parameter. Selain itu, seqtidak pernah bisa mengambil ekspresi dan memutuskan "apakah ini ⊥?" (lih. Masalah Berhenti), seqhanya dapat mencoba untuk mengevaluasinya, dan itu sendiri berbeda dengan ⊥.

Yang seqdilakukan adalah mengevaluasi parameter pertama (tidak sepenuhnya, tetapi untuk "bentuk normal kepala lemah" [1], yaitu ke konstruktor paling atas), lalu mengembalikan parameter kedua. Jika parameter pertama kebetulan (yaitu, perhitungan non terminating) maka mengevaluasi itu menyebabkan seqnon-terminate, dan dengan demikian seq ⊥ a = ⊥.

[1] Teorema Gratis di Hadirat seq - Johann, Voigtlander http://www.iai.uni-bonn.de/~jv/p76-voigtlaender.pdf


Spesifikasi yang saya berikan untuk seq adalah definisi seq karena itulah yang dikatakan oleh laporan Haskell 2010 di Bagian 6.2. Definisi operasi seq Anda tidak didukung oleh laporan Haskell 2010: kata-kata "head normal form" hanya muncul satu kali dalam laporan dalam konteks yang sama sekali berbeda. Ini juga tidak konsisten dengan pemahaman saya bahwa GHC akan sering mengurangi argumen kedua menjadi seq sebelum argumen pertama, atau argumen pertama tidak akan berkurang sama sekali karena penganalisis ketelitian telah membuktikan bahwa non-bottom secara statis.
Russell O'Connor

Parametrisitas tidak secara langsung mengatakan bahwa kita tidak dapat menerapkan dekonstruktor apa pun, juga tidak mengatakan kita tidak pernah dapat mengidentifikasi parameter pertama dengan nilai fungsi. Semua parametercity mengatakan untuk kalkulus lambda polimorfik dengan fixpoint adalah bahwa seq dapat menyerap fungsi yang ketat, atau lebih umum, hubungan ketat tertentu untuk istilah mengandung seq. Saya akui itu masuk akal bahwa parametrikitas dapat digunakan untuk membuktikan (\ x -> ⊥) & ne; ⊥, tapi saya ingin melihat bukti yang kuat.
Russell O'Connor

Dalam hal fungsi f : forall a . a -> T(di mana Tada beberapa tipe lain), maka ftidak dapat menerapkan dekonstruktor apa pun pada argumen pertamanya karena tidak tahu dekonstruktor mana yang akan diterapkan. Kami tidak dapat melakukan "kasus" pada jenis. Saya telah mencoba untuk meningkatkan jawaban di atas (termasuk mengutip informasi tentang seqmengevaluasi bentuk kepala normal).
dorchard

Saya dapat mencoba melakukan bukti yang kuat nanti jika saya menemukan waktu (menggunakan hubungan dengan gaya Reynolds mungkin merupakan pendekatan yang baik).
dorchard

@ RussellO'Connor: deskripsi seq tidak "tidak konsisten" dengan perilaku itu, itu hanya spesifikasi operasional (dan perilaku adalah optimasi yang tidak mengubah hasil akhir).
Blaisorblade

2

λx.λx.

Samson Abramsky mempertimbangkan masalah ini sejak lama dan menulis sebuah makalah berjudul " The Lazy Lambda Calculus ". Jadi, jika Anda menginginkan definisi formal, di sinilah Anda akan melihat.


1
Rupanya, perincian ini hanya ditentukan dengan memasuki "Haskell kernel". Di mana itu didefinisikan? Laporan itu mengatakan, dalam Sec. 1.2 : "Meskipun kernel tidak ditentukan secara formal, pada dasarnya ini adalah varian yang agak bergula dari kalkulus lambda dengan semantik denotasional langsung. Terjemahan dari masing-masing struktur sintaksis ke dalam kernel diberikan ketika sintaks diperkenalkan."
Blaisorblade

Laporan Haskell 2010 mengatakan hal yang sama , luar biasa.
Blaisorblade

Terima kasih untuk referensi ke Abramsky! Saya membaca skim untuk melihat bagaimana ia menjawab pertanyaan, dan saya datang dengan jawaban berikut: cstheory.stackexchange.com/a/21732/989
Blaisorblade

2

Membuktikan bahwa λ x. Ω ‌ ≠ Ω in adalah salah satu tujuan yang Abramsky tetapkan untuk teori kalkulus lambda malasnya (halaman 2 makalahnya , sudah dikutip oleh Uday Reddy), karena keduanya dalam bentuk kepala normal yang lemah. Pada definisi 2.7, ia membahas secara eksplisit bahwa eta-reduksi λ x. M x → M umumnya tidak valid, tetapi dimungkinkan jika M berakhir di setiap lingkungan. Ini tidak berarti bahwa M harus menjadi fungsi total - hanya bahwa mengevaluasi M harus diakhiri (dengan mengurangi menjadi lambda, misalnya).

Pertanyaan Anda tampaknya dimotivasi oleh masalah praktis (kinerja). Namun, meskipun Laporan Haskell mungkin kurang dari sepenuhnya jelas, saya ragu bahwa menyamakan λ x. ⊥ ‌ dengan ⊥ akan menghasilkan implementasi Haskell yang berguna; apakah itu mengimplementasikan Haskell '98 atau tidak masih bisa diperdebatkan, tetapi memberikan komentar, jelas bahwa penulis bermaksud untuk menjadi demikian.

Akhirnya, bagaimana seq menghasilkan elemen untuk tipe input yang sewenang-wenang? (Saya tahu QuickCheck mendefinisikan typeclass sewenang-wenang untuk itu, tetapi Anda tidak diizinkan untuk menambahkan kendala seperti itu di sini) Ini melanggar parametrik.

Diperbarui : Saya tidak berhasil mengkodekan hak ini (karena saya tidak begitu lancar di Haskel), dan memperbaiki ini sepertinya memerlukan runSTwilayah bersarang . Saya mencoba menggunakan sel referensi tunggal (dalam monad ST) untuk menyimpan elemen arbitrer seperti itu, membacanya nanti, dan membuatnya tersedia secara universal. Parametrisitas membuktikan bahwa di break_parametricitybawah ini tidak dapat didefinisikan (kecuali dengan kembali ke bawah, misalnya kesalahan), sementara itu bisa memulihkan elemen yang seq diusulkan akan menghasilkan.

import Control.Monad.ST
import Data.STRef
import Data.Maybe

produce_maybe_a :: Maybe a
produce_maybe_a = runST $ do { cell <- newSTRef Nothing; (\x -> writeSTRef cell (Just x) >> return x) `seq` (readSTRef cell) }

break_parametricity :: a
break_parametricity = fromJust produce_maybe_a

Saya harus mengakui bahwa saya agak kabur memformalkan bukti parametrik yang diperlukan di sini, tetapi penggunaan parametrikitas informal ini merupakan standar di Haskell; tetapi saya belajar dari tulisan Derek Dreyer bahwa teori yang dibutuhkan dengan cepat dikerjakan dalam tahun-tahun terakhir ini.

EDIT:

  • Saya bahkan tidak yakin apakah Anda memerlukan ekstensi itu, yang dipelajari untuk bahasa seperti ML, imperatif, dan tidak ketik, atau apakah teori klasik parametrik meliputi Haskell.
  • Juga, saya menyebut Derek Dreyer hanya karena saya baru saja menemukan karya Uday Reddy - saya baru tahu tentang hal itu dari "Esensi Reynolds". (Saya hanya mulai benar-benar membaca literatur tentang parametrik dalam sebulan terakhir ini).

Mengevaluasi (\x -> writeSTRef cell (Just x) >> return x)input acak tidak menjalankan penulisan ke sel. Hanya perintah ST yang membuatnya menjadi urutan yang dilewati runSTyang pernah dieksekusi. Demikian pula, menjalankan main = (putStrLn "Hello") `seq` (return ())tidak mencetak apa pun ke layar.
Russell O'Connor

@ RussellO'Connor, tentu saja Anda benar - pengujian sulit karena seq tidak memiliki perilaku yang kita diskusikan. Tapi saya masih berpikir elemen pembangkit merusak parametrik per se. Saya akan mencoba memperbaiki jawaban untuk mencontohkan.
Blaisorblade

Hm, perbaikan yang jelas untuk jawabannya memerlukan wilayah runST yang bersarang dan menggunakan sel dari wilayah luar di bagian dalam, tetapi itu tidak diizinkan.
Blaisorblade
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.