大文字と小文字の使い分け - lisp-cookbook-ja/common-lisp GitHub Wiki

コーディングスタイル

Common Lispでは伝統的なLISPと同様シンボルは読取時に大文字に畳み込まれます(case folding)。

(※畳み込みをエスケープすすることも可能です|で囲んだり文字に\を前置します。)

伝統的なLISPでは、この性質を利用してソースコード上で見やすさへの配慮や、単に個人的な趣味で大文字小文字を使い分けることが行なわれています。 下記に代表的な例を挙げます。

formatのフォーマット指示記号だけ大文字にする

大文字と小文字の使い分けの最も一般的なものですが、主に見やすさと伝統に由来するものと思われます

(format nil "~A: ~D => ~A~%" foo bar baz)

返り値を強調するために大文字にする

(defun foo (x)
  ...
  ....
  (return-from foo NIL)
  ...)

関数名だけ大文字にする

(defun FOO-to-BAR (..)
  ...)

間に挟まるものが長くなる場合、対になるものを大文字にする

;; mapcar
(MAPCAR (lambda (x y z)
          .....
          (let ((...))
            .....
            .....
            (cond ((...))
                  ....)
            (let ((....))
              ....
              ....
              ....)))
        (LIST X Y Z))

;; coerce
(COERCE (list ....
          .....
          (let ((...))
            .....
            .....
            (cond ((...))
                  ....)
            (let ((....))
              ....
              ....
              ....)))
        'VECTOR)

ifで述語/then部が長い場合、各部分の開始行を大文字にする

(IF (AND FOO BAR BAZ
         ...
         ...)
    (COND ((...)
           (let ((...))
             .....
             .....
             (cond ((...))
                   ....)
             (let ((....))
               ....
               ....
               ....)))
          (...)
          (t ...))
    (LET ((X Y Z))
      .....
      .....
      (cond ((...))
            ....)
      (let ((....))
        ....
        ....
        ....)))

condのデフォルト節のTを区別しやすいように大文字にする

(cond ((...)
       (..)
      ((...))
      ((......))
      (T ...)))

その他

マクロの定義で展開結果となる部分(可変ではない部分)を大文字にする

(defmacro ONCE-ONLY (variable-list &body body)
  (dolist (variable variable-list)
    (if (not (symbolp variable))
        (error "~S is not a variable" variable)))
  (let ((bind-vars (gensym))
        (bind-vals (gensym))
        (tem (gensym)))
    `(LET ((,bind-vars NIL)
           (,bind-vals NIL))
       (LET ((RESULT ((LAMBDA ,variable-list ,@body)
                       ,@(loop for variable in variable-list
                               collect `(IF (OR (ATOM ,variable)
                                                (EQ (CAR ,variable) 'QUOTE)
                                                (EQ (CAR ,variable) 'FUNCTION))
                                            ,variable
                                          (LET ((,tem (GENSYM)))
                                            (PUSH ,tem ,bind-vars)
                                            (PUSH ,variable ,bind-vals)
                                            ,tem))))))
         (IF (NULL ,bind-vars)
             RESULT
           `((LAMBDA ,(nreverse ,bind-vars) ,result) ,@(nreverse ,bind-vals)))))))

パッケージ名付きの場合、シンボル名だけを大文字にする

(drakma:HTTP-REQUEST ...)

恐らく個人的なこだわり

(DefMacro MY-MACRO (... ) )

(DefClass FOO ()
  ...)

(DefMethod MY-METHOD (...) 
  ...)

議論

  • clispの「-modern」オプションのように大文字と小文字を区別する(read時に大文字にしない)環境も存在するので、大文字と小文字を区別しないことに過度に依存するのはよくないかもしれません。
  • Allegro CLのmlisp等CLISP以外にもあるかと思いますが、処理系のオプションで大文字小文字を有効にすることの是非についてはc.l.lでも激しい議論になりがちですね。 今のところ大文字と小文字を区別した環境で動くこと考慮するということは仕様外の可搬性を求めることになるかと思いますし、どちらかといえば過度に依存して良くないのは「大文字と小文字を区別することを前提としたコード」ではないでしょうか。詳しい議論はc.l.l等で度々されているようですね。 --g000001
  • 上の発言は大文字小文字を区別しない環境で動作することを前提に、大文字小文字を区別する環境でも動くことを意識した方がいいんじゃないかなぁという意図でした。「大文字と小文字を区別することを前提としたコード」はCLとしては間違っているので全く意識していませんでした。 -- NANRI