2014-09-29 20 views
8

Emacs Lisp ve Common Lisp'in sözdizimi ile çok yakından ilişkili olduğunu düşündüğümden, RosettaCode adresinde bulduğum örnek kodu takip edebilirim, ancak yanlış olduğum ortaya çıktı.ELisp'te nasıl adlandırılmış argümanlar yapabilirim?

söz konusu kod şuna benzer:

(defun print-name (&key first (last "?")) 
    (princ last) 
    (when first 
    (princ ", ") 
    (princ first)) 
    (values)) 

Ve RosettaCode göre aşağıdaki yapmalıdır:

Şimdi
> (print-name) 
    ? 
> (print-name :first "John") 
    ?, John 
> (print-name :last "Doe") 
    Doe 
> (print-name :first "John" :last "Doe") 
    Doe, John 

, olay şu;

*** Eval error *** Wrong number of arguments: (lambda (&key first (last "?")) (princ la\ 
st) (if first (progn (princ ", ") (princ first))) (values)), 0 

Bunu demek oluyor bilmek lisp yeterli routined değilim ve öne vardır Googling hiçbir miktar: Ben elisp yorumlayıcı bu işlevi çalıştırmayı denediğinizde, aşağıdaki hatayı alıyorum Bana bir cevap daha yakın.

Emacs Lisp'te bunu yapmanın doğru yolu nedir?

cevap

2

Maalesef elispdoes not support named arguments per-se. Ancak, alist'u check this for a guide on alists işlevine geçirerek bu özelliği taklit edebilirsiniz. Özünde

bu sen/kontrol, her iki ambalajın ( alist argümanların bileşimi) dikkat çekmek ve değişkenleri (ayrışma unwrapping gerekir, dolayısıyla işlev bir harita benzeri veri yapısı geçmesi anlamına gelir gerekli/isteğe bağlı değerler).

(print-name '((first . "John") (last . "Doe"))) 

Okuma daha basittir:

(assoc 'last '((first . "John") (last . "Doe"))) 
; => (last . "Doe") 
(assoc 'middle '((first . "John") (last . "Doe"))) 
; => nil 
: sadece ilgili değeri elde etmek için assoc kullanmak girdi yapısının

oluşturma basittir, sadece Eksileri değişken sembolünün hücreleri ve değerini oluşturmak Dolayısıyla

, print-name bu gibi görünebilir:

(defun print-name (alist) 
    (let ((first (assoc 'first alist)) 
     (last (assoc 'last alist))) 
    (if last 
     (princ (cdr last)) 
     (error "Missing last name!")) 
    (when first 
     (princ ", ") 
     (princ (cdr first))))) 
+5

deyimsel, yerine args' dinlenme '& kullanmayı tercih ediyorum ve' az sözdizimsel dağınıklığı vardır plist olarak args', ayrıştırmak: '(baskı

Birlikte bu sadece senin soru gibi print-name çağrı sağlar -name: ilk "John": son "Doe") '. – lunaryorn

12

elisp en defun&key (olsa &optional ve &rest, destekliyor) desteklemiyor. &key kullanarak işlevleri tanımlamanıza olanak veren bir makro vardır. Emacs 24.3 yılında ve daha sonra cl-lib gerektirebilir ve cl-defun kullanın: cl-lib kütüphane tercih edilir

(require 'cl) 
(defun* print-name (&key first (last "?")) 
    ... 

: önceki Emacs sürümlerinde

(require 'cl-lib) 
(cl-defun print-name (&key first (last "?")) 
    ... 

, aynı işlevselliği adı defun* altında cl kütüphanede cl için, cl- ile tüm sembolleri önekleyerek ad alanını düzenli tutar; Ancak, daha önceki Emacs sürümleriyle uyumluluğa ihtiyacınız varsa, cl ve defun*'u tercih edebilirsiniz.


Örnekdeki işlev, values işlevine de bir çağrı içerir. Bu işlev, Ortak Lisp'e özgüdür, ancak cl-lib ve 'da values olarak cl-values olarak kullanılabilir. Bununla birlikte, alternatifler Common Lisp karşılığı ile tamamen aynı şekilde çalışmazlar. Ortak Lisp çoklu dönüş değerleri kavramına sahiptir. Örneğin, (values 1 2 3) numaralı telefonu çağırmak üç değer döndürür - ve yukarıdaki gibi (values) çağrısı sıfır değerleri döndürür. Emacs Lisp işlevleri, listeler yoluyla çoklu dönüş değerlerini taklit eder ve eşleşmek için multiple-value-bind'u yeniden tanımlar. Bu, (cl-values) aramasının nil (boş liste) değerini döndüreceği anlamına gelir.

Böyle bir Emacs Lisp işlevinde, dönüş değerini açıkça nil olarak belirtebilir veya yalnızca tamamen bırakabilirsiniz, son formun dönüş değeri, işlevin dönüş değeri olarak bırakılır; dönüş değerini kullanması beklenmemektedir.

+0

bu tam olarak çalışmıyor, "Sembolün fonksiyon tanımı geçersiz" diyen bir hata alıyorum: değerler –

+0

Doğru, "değerler" işlevi başka bir Common Lisp özelliğidir. Cl-lib'de 'cl-values' denir. – legoscia

+0

Bunu yapmak, herhangi bir şeyi yazdırmak yerine sıfırdan döndürür ... En azından bir hata üretmez –

12

Emacs Lisp doğrudan anahtar kelime argümanları desteklemediği olduğundan, bu taklit gerekir ya cl-defun diğer yanıtında olduğu gibi, ya tarafından plist olarak argümanları ayrıştırma ile:

(defun print-name (&rest args) 
    (let ((first (plist-get args :first)) 
     (last (or (plist-get args :last) "?"))) 
    (princ last) 
    (when first 
     (princ ", ") 
     (princ first)))) 

&rest args için Emacs söyler tüm işlev argümanlarını tek bir listeye koy. plist-get, bir özellik listesinden bir değer çıkarır; yani, (key1 value1 key2 value2 …) biçiminin bir listesi. Etkili olarak, bir plist düzleştirilmiş bir alistir.

> (print-name) 
    ? 
> (print-name :first "John") 
    ?, John 
> (print-name :last "Doe") 
    Doe 
> (print-name :first "John" :last "Doe") 
    Doe, John