Saya telah melihat progn
cukup 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!
use-package
akan membungkusprogn
Anda: config bentuk jika hilang. Cobalah: Anda bisa memberi titik di akhir a(use-package ...)
dan meneleponM-x pp-macroexpand-last-sexp
untuk melihat bagaimana makro diperluas. Anda akan melihat bahwa itu identik untuk dua contoh ini.progn
diperlukan: emacs.stackexchange.com/questions/39172/…Jawaban:
progn
biasanya digunakan ketika berhadapan dengan makro. Beberapa makro (use-package
adalah 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
progn
dan dengan demikian ada 1 formulir setelahnya:config
. Yang kedua, ada 3 bentuk . Jikause-package
makro hanya mengharapkan 1 formulir berikut:config
, maka itu akan menyebabkan kesalahan.Perlu dicatat bahwa menggunakan
progn
karya dalam kedua kasus, sementara menghilangkannya hanya berfungsi jika makro menerima beberapa bentuk. Akibatnya, beberapa orang lebih suka untuk selalu menggunakanprogn
, karena itu akan selalu berhasil.sumber
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 semuaprogn
tidak: itu memungkinkan Anda memberikan satu jenis kelamin yang ketika dievaluasi mengevaluasi argumen jenis kelaminprogn
secara berurutan. Bandingkan(if true (progn a b c))
dengan(when true a b c)
. Dalam kedua kasus,a
,b
, danc
dievaluasi secara berurutan.use-package
memungkinkan beberapa formulir di:config
dan:init
.progn
sexp 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 yangprogn
ada untuk makro, dan bahwa 99% penggunaannya untuk makro, menyesatkan, IMO.progn
adalah tentang menyekop urutan evaluasi menjadi satu jenis kelamin (agar sesuai dengan argumen yang diharapkan), dan karena itu tentang efek samping .progn
diperkenalkan 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. Lihatprogn
bagaimana Emacs sendiri memperkenalkanprogn
kepada programmer Elisp. Lihatzap-to-char
kode untuk case use sederhana.progn
memiliki 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.Alasan paling penting untuk progn dijelaskan pada baris pertama dari dokumentasi progn (penekanan ditambahkan):
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 :
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 ?
sumber
if
), tetapi urutan evaluasi normal (misalnya formulir tingkat atas, badan fungsi, dll.) Bersifat tekstual. Tentu saja, pada tingkat tertentu itu implisitprogn
, tetapi biasanya bukan itu yang Anda gunakanprogn
dalam kode Anda sendiri.(elisp) Sequencing
yang Anda tautkan mengatakan itu semua.Cara yang lebih baik untuk memahami apa
progn
itu dengan membandingkannya dengan keluarga:prog1
danprog2
. Bagiann
atau1
atau2
dari nama singkatan dari pernyataan dari daftar yang hasilnya Anda minati. Dengan kata lain,progn
akan mengembalikan hasil dari pernyataan terakhir yang dikandungnya, sedangkanprog1
akan mengembalikan yang pertama, dan yang serupa untukprog2
.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
prog1
danprog2
sangat 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
progX
keluarga masuk.Dalam bahasa mirip C, fitur ini kadang-kadang dikenal sebagai titik urutan (yaitu
;
dan,
misalnya).progn
sama 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 tidakprogn
sering melihat itu digunakan, namun itu adalah salah satu blok bangunan yang penting, ketika datang untuk membangun abstraksi bahasa tingkat yang lebih tinggi (sa macro).sumber