Kapan / mengapa saya harus menggunakan progn?


19

Saya telah melihat progncukup banyak digunakan ketika saya menelusuri file konfigurasi pengguna Emacs yang berpengalaman. Saya menemukan penjelasan yang bagus tentang iniprogn , tetapi yang paling saya ingin tahu adalah, apa manfaat menggunakan fungsi ini? Ambil contoh cuplikan ini (diambil dari konfigurasi Sacha Chua ):

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (progn
    (global-undo-tree-mode)
    (setq undo-tree-visualizer-timestamps t)
    (setq undo-tree-visualizer-diff t)))

Apakah ada perbedaan besar antara konfigurasi di atas dan ini?

(use-package undo-tree
  :defer t
  :ensure t
  :diminish undo-tree-mode
  :config
  (global-undo-tree-mode)
  (setq undo-tree-visualizer-timestamps t)
  (setq undo-tree-visualizer-diff t))

Saya merasa contoh pertama entah bagaimana lebih bersih, meskipun memiliki lebih banyak sintaksis, dan intuisi saya adalah bahwa mungkin ada semacam peningkatan kinerja dari penggunaan progn, tetapi saya tidak yakin. Terima kasih atas wawasannya!


7
Dalam kasus khusus ini tidak ada perbedaan: use-packageakan membungkus prognAnda: config bentuk jika hilang. Cobalah: Anda bisa memberi titik di akhir a (use-package ...)dan menelepon M-x pp-macroexpand-last-sexpuntuk melihat bagaimana makro diperluas. Anda akan melihat bahwa itu identik untuk dua contoh ini.
glukas

Sebuah contoh di mana progndiperlukan: emacs.stackexchange.com/questions/39172/…
npostavs

Jawaban:


11

prognbiasanya digunakan ketika berhadapan dengan makro. Beberapa makro ( use-packageadalah makro, yang terakhir saya periksa) hanya menerima 1 formulir , di mana yang lain mengkonsumsi semua formulir yang tersisa .

progn digunakan dalam kasus sebelumnya untuk mengubah urutan bentuk menjadi bentuk tunggal.

Dalam contoh Anda, yang pertama menggunakan progndan dengan demikian ada 1 formulir setelahnya :config. Yang kedua, ada 3 bentuk . Jika use-packagemakro hanya mengharapkan 1 formulir berikut :config, maka itu akan menyebabkan kesalahan.

Perlu dicatat bahwa menggunakan prognkarya dalam kedua kasus, sementara menghilangkannya hanya berfungsi jika makro menerima beberapa bentuk. Akibatnya, beberapa orang lebih suka untuk selalu menggunakan progn, karena itu akan selalu berhasil.


15
Ini benar-benar tidak ada hubungannya dengan makro. Beberapa fungsi dan makro memiliki apa yang disebut "implisit progn", artinya mereka menerima sejumlah sexps sebagai argumen terpisah dan mengevaluasinya secara berurutan. Yang lain tidak, dan sebaliknya hanya mengharapkan / mengizinkan satu argumen di mana Anda mungkin ingin mengevaluasi beberapa jenis kelamin secara berurutan. Itu semua progntidak: itu memungkinkan Anda memberikan satu jenis kelamin yang ketika dievaluasi mengevaluasi argumen jenis kelamin prognsecara berurutan. Bandingkan (if true (progn a b c))dengan (when true a b c). Dalam kedua kasus, a, b, dan cdievaluasi secara berurutan.
Drew


4
Saya tidak setuju bahwa 99% dari kasus penggunaan adalah untuk makro dll. Setiap fungsi atau makro dapat diberikan prognsexp yang mengandung beberapa sexps yang dievaluasi untuk efek sampingnya, sebelum mengembalikan hasil yang terakhir. Ini benar-benar tidak ada hubungannya dengan makro. Makro "sebagai contoh" tidak masalah. Memberi kesan yang prognada untuk makro, dan bahwa 99% penggunaannya untuk makro, menyesatkan, IMO. prognadalah tentang menyekop urutan evaluasi menjadi satu jenis kelamin (agar sesuai dengan argumen yang diharapkan), dan karena itu tentang efek samping .
Drew

5
1. progndiperkenalkan di Lisp 1.5 (lihat bagian Fitur Program ), pada tahun 1962, jauh sebelum makro ditambahkan ke Lisp. Tujuannya adalah untuk mengevaluasi ekspresi untuk efek sampingnya secara berurutan. 2. Lihat prognbagaimana Emacs sendiri memperkenalkan prognkepada programmer Elisp. Lihat zap-to-charkode untuk case use sederhana.
Drew

2
Kami dapat setuju untuk tidak setuju. Maksud saya adalah bahwa prognmemiliki tidak ada hubungannya dengan macro. Tujuannya tentu saja " untuk mengirimkan beberapa bentuk sebagai satu bentuk " (kata-kata Anda) - baik untuk fungsi atau makro atau bentuk khusus, tetapi juga untuk " Eval BODY bentuk secara berurutan dan mengembalikan nilai yang terakhir " (string doc ). Sekarang seperti biasa ("hari ini", memang!). Evaluasi yang terurut penting hanya untuk efek samping, jelas. Kasus penggunaan yang diberikan (makro atau tidak) mungkin atau mungkin tidak peduli dengan urutan evaluasi, tetapi itu tidak relevan. Dan Emacs Lisp tidak luar biasa dalam hal apa pun dalam hal ini.
Drew

10

Alasan paling penting untuk progn dijelaskan pada baris pertama dari dokumentasi progn (penekanan ditambahkan):

progn adalah bentuk khusus yang menyebabkan setiap argumennya dievaluasi secara berurutan dan kemudian mengembalikan nilai yang terakhir.

Tambahan:

Tanpa progn , urutan tidak dijamin, terutama jika ekspresi selanjutnya tergantung pada efek samping atau nilai pengembalian ekspresi sebelumnya. progn menegakkan urutan eksekusi sama dengan urutan tekstual. Membantu untuk tidak membingungkan eksekusi dengan parsing. Perilaku ini kembali ke dasar-dasar struktur kontrol lisp dan pemrograman fungsional. Berikut ini kutipan (penekanan ditambahkan) dari manual referensi lisp :

Struktur kontrol bawaan adalah bentuk khusus karena subformanya tidak perlu dievaluasi atau tidak dievaluasi secara berurutan .

Apakah progn meningkatkan kinerja?

Mengurai kinerja, tidak. Kinerja eksekusi, tidak. Paling-paling itu mungkin sama tetapi tidak pernah secara ajaib meningkatkan kinerja.

Kapan progn digunakan ?

... paling sering di dalam pelepas-lindung, dan, atau , atau di bagian saat itu jika .


Saya tidak yakin mengapa itu sangat penting. Emacs selalu mengevaluasi secara berurutan.
lunaryorn

2
@Lunaryorn melihat jawaban yang diperbarui.
Pengguna Emacs

Saya tidak yakin apakah saya mengerti hasil edit Anda. Secara alami ada formulir khusus dengan urutan evaluasi yang berbeda (misalnya if), tetapi urutan evaluasi normal (misalnya formulir tingkat atas, badan fungsi, dll.) Bersifat tekstual. Tentu saja, pada tingkat tertentu itu implisit progn, tetapi biasanya bukan itu yang Anda gunakan progn dalam kode Anda sendiri.
lunaryorn

Saya pikir simpul manual Elisp (elisp) Sequencingyang Anda tautkan mengatakan itu semua.
Basil

10

Cara yang lebih baik untuk memahami apa prognitu dengan membandingkannya dengan keluarga: prog1dan prog2. Bagian natau 1atau 2dari nama singkatan dari pernyataan dari daftar yang hasilnya Anda minati. Dengan kata lain, prognakan mengembalikan hasil dari pernyataan terakhir yang dikandungnya, sedangkan prog1akan mengembalikan yang pertama, dan yang serupa untuk prog2.

Hari ini fungsi ini tampaknya sedikit canggung karena kita belajar mengharapkan program untuk kembali dalam pernyataan terakhir, atau untuk menginstruksikannya secara eksplisit apa yang harus dikembalikan. Dengan demikian prog1dan prog2sangat jarang digunakan. Namun, jika Anda memikirkannya, itu masuk akal, dan inilah caranya:

Bahasa pemrograman yang berbeda menggunakan strategi yang berbeda untuk menggambarkan semantik mereka. Keluarga Lisp dulu terikat erat dengan semantik denotasional. Tanpa banyak perincian, semantik semacam ini memiliki kesulitan khusus dengan sesuatu yang kita kenal sebagai "pernyataan", yang bukan "ekspresi". Makna kode biasanya dianggap dalam hal kombinasi fungsi, sementara "pernyataan" yang bahkan tidak dapat digambarkan sebagai fungsi (karena tidak mengevaluasi apa pun) dengan demikian sulit untuk dihadapi. Namun, karena Lisp mengizinkan efek samping, kadang-kadang seorang programmer ingin menggunakan ekspresi tanpa menggunakan nilainya dengan cara yang tidak memengaruhi ekspresi yang mengikutinya. Dan di sinilah progXkeluarga masuk.

Dalam bahasa mirip C, fitur ini kadang-kadang dikenal sebagai titik urutan (yaitu ;dan ,misalnya). prognsama pentingnya untuk bahasa seperti Lisp seperti untuk bahasa seperti ;C. Ini adalah fitur dasar dari bahasa yang tidak dapat dengan mudah diganti. Namun, tidak seperti bahasa C-style, Lisp cenderung membangun abstraksi sintaksis dengan sepenuhnya menyembunyikan sintaksis dari level yang lebih rendah. Dan ini mungkin mengapa Anda tidak prognsering melihat itu digunakan, namun itu adalah salah satu blok bangunan yang penting, ketika datang untuk membangun abstraksi bahasa tingkat yang lebih tinggi (sa macro).

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.