Ikat banyak nilai secara langsung dari daftar tanpa mengikat daftar itu sendiri

12

Apakah mungkin untuk menetapkan beberapa nilai pengembalian langsung ke variabel tanpa melalui variabel sementara di Emacs Lisp?

Misalnya, katakanlah saya memiliki fungsi yang mengembalikan daftar dua daftar:

(defun test-func ()
  (setq a '(a b))
  (setq b '(c d))
  `(,a ,b))

Jika saya ingin menetapkan nilai pengembalian pertama list-adan nilai pengembalian kedua list-b, saya bisa melakukan ini dengan menggunakan variabel sementara temp, misalnya:

(let* ((temp (test-func)) (list-a (car temp)) (list-b (cadr temp)))
  (message-box (prin1-to-string list-a))
  (message-box (prin1-to-string list-b)))

Apakah mungkin melakukan ini dengan lebih sederhana? (Saya terbiasa dengan Perl dan Python di mana Anda tidak harus menentukan variabel sementara)

Håkon Hægland
sumber
2
Anda dapat mencoba cl-destructuring-bindmakro. Juga, apakah Anda benar-benar ingin menggunakannya setqdi dalam defun? setqmenciptakan variabel "khusus" (dapat diakses secara global), sesuatu yang biasanya Anda letakkan di luar fungsi (karena ada sedikit makna dalam mendeklarasikan variabel yang sama lebih dari satu kali, sementara fungsi dimaksudkan untuk dijalankan lebih dari satu kali).
wvxvw
@wvxvw Terima kasih! Ya saya lupa menggunakan letdi dalam fungsi .. Saya tidak berencana untuk mengatur variabel global :)
Håkon Hægland

Jawaban:

8

Common Lisp memiliki fasilitas khusus - beberapa nilai , dan pustaka kompatibilitas Emacs Lisp mengemulasikannya menggunakan daftar .

Dengan begitu bisa Anda lakukan

(defun test-fun ()
  (let ((a 1) (b 2))
    (cl-values a b)))

(cl-multiple-value-bind (a b) (test-fun)
  ...)

(muat cl-libdan gunakan cl-awalan untuk semua fungsionalitas CL di EL).

NB : jika Anda melihat jawaban SO terkait di atas, Anda akan melihat bahwa meniru MV dengan daftar adalah, secara halus, suboptimal (lihat juga @ komentar Stefan bawah).

sds
sumber
Apakah ada keuntungan menggunakan multiple-value-bindbukan cl-multiple-value-bind(hanya yang terakhir tampaknya didokumentasikan dalam manual gnu.org/software/emacs/manual/html_node/cl/Multiple-Values.html )?
Håkon Hægland
3
@ HåkonHægland Mereka memiliki fungsi yang sama, tetapi Anda harus menggunakan yang terakhir . The clpaket ini tidak dimaksudkan untuk digunakan lagi. Anda harus selalu menggunakan cl-libpaket sebagai gantinya, yang mendefinisikan fungsi dengan cl-awalan ..
Malabarba
1
Saya akan merekomendasikan menentang penggunaan cl-values: ini adalah emulasi "upaya terbaik" dari CommonLisp valuestetapi tidak benar-benar kompatibel karena semua yang dilakukannya adalah mengembalikan daftar (yaitu semacam kebohongan), dan dalam pengalaman saya orang cepat atau lambat akan berakhir memanipulasi mereka sebagai daftar (yaitu melanggar abstraksi): daftar penggunaan yang lebih baik secara eksplisit (dan jika Anda tidak suka pcase-let, maka gunakan cl-destructuring-binddaripada cl-multiple-value-bind).
Stefan
4

Selain mengandalkan cl-libpaket kompatibilitas, cara yang disarankan di Elisp adalah menggunakan pcase:

(defun test-fun
  (let ((a '(a b))
        (b '(c d)))
    `(,a ,b)))

(defun other-test-fun ()
  (pcase-let ((`(,a ,b) (test-fun)))
    (message "a = %s; b = %s" a b)))

Di samping pcase-let, ada juga pcase-dolist, pcase-lambdadan pcaseitu sendiri.

Stefan
sumber