Looking for common-lisp Answers? Try Ask4KnowledgeBase
Looking for common-lisp Keywords? Try Ask4Keywords

common-lispcommon-lispの使い方


備考

これはCommon Lispの単純なhello world関数です。例では、 Hello, World!というテキストが印刷されますHello, World! (引用符はなく、改行が続きます)を標準出力に追加します。

Common Lispは、REPLとして知られるインタフェースを使用して対話的に使用されるプログラミング言語です。 REPL(Eval Print Loopを読む)では、コードを入力して評価(実行)し、すぐに結果を見ることができます。 REPLのプロンプト(実行するコードをタイプするポイント)は、 CL-USER>示されます。 CL-USER以外のものが>前に現れることがあり>が、これはまだREPLです。

プロンプトの後に、通常は単一の単語(つまり変数名)またはフォーム( ()間に囲まれた単語/フォームのリスト)(つまり、関数呼び出しや宣言など)があります。次の行には、プログラムが出力する出力(またはプログラムが何も出力しない場合は何も出力されません)と、式を評価することによって返される値があります。通常、式は1つの値を返しますが、複数の値を返す場合は、1行に1回表示されます。

バージョン

バージョン発売日
Common Lisp 1984-01-01
ANSIコモン・リスプ 1994-01-01

基本式

REPLで基本的な表現を試してみましょう:

CL-USER> (+ 1 2 3)
6
CL-USER> (- 3 1 1)
1
CL-USER> (- 3)
-3
CL-USER> (+ 5.3 (- 3 2) (* 2 2))
10.3
CL-USER> (concatenate 'string "Hello, " "World!")
"Hello, World!"
CL-USER> 
 

Common Lispプログラムの基本的なビルディングブロックはフォームです。私たちは関数の形を持っているこれらの例では、それは最初の要素がオペレータ(または関数)と残りの要素であるリストとして書かれた式で、あるオペランドを(これは「プレフィックス表記法」と呼ばれる、または「ポーランド記法されています")。 REPLにフォームを書くと、その評価が行われます。この例では、引数が定数、文字列、記号(型の名前である'string の場合)である単純式を見ることができます。また、算術演算子は任意の数の引数を取ることができます。

括弧は構文の不可欠な部分であり、他のプログラミング言語のように自由に使用することはできないことに注意することが重要です。たとえば、次のようなエラーがあります。

(+ 5 ((+ 2 4)))
> Error: Car of ((+ 2 4)) is not a function name or lambda-expression. ...
 

Common Lispでは、フォームはデータ、シンボル、マクロフォーム、特殊フォーム、ラムダフォームでもあります。それらは評価されるように書くことができ、ゼロ、1つ、またはそれ以上の値を返したり、マクロに入力して他の形式で変換することができます。

Common Lisp学習リソース

オンライン書籍

これらはオンラインで自由にアクセスできる本です。

オンライン参考文献

  • Common Lisp HyperspecCommon Lisp 言語リファレンスドキュメントです。
  • Common Lisp Cookbookは、便利なLispのレシピのリストです。 CL情報の他のオンラインソースのリストも含まれています。
  • Common Lisp Quick Referenceには、印刷可能なLispリファレンスシートがあります。
  • Lispdoc.comは、ドキュメントのために、いくつかのLisp情報ソース(Practical Common Lisp、Successful Lisp、On Lisp、HyperSpec)を検索します。
  • L1sp.orgはドキュメントのリダイレクトサービスです。

オフライン書籍

あなたが購入しなければならない、または図書館から貸し出される可能性のある書籍です。

オンラインコミュニティ

図書館

あらかじめパッケージ化されたLisp環境

これらは、必要なものすべてがあらかじめパッケージ化され、事前に設定されているため、インストールが簡単で使い始めやすいLisp編集環境です。

  • PortacleはポータブルでマルチプラットフォームのCommon Lisp環境です。スライム、SBCL(一般的なCommon Lispの実装)、Quicklisp、Gitを使って、ややカスタマイズされたEmacsを提供しています。インストールは必要ありませんので、非常に簡単で簡単な方法です。
  • Lispboxは、Windows、Mac OSX、Linux用のアーカイブとしてあらかじめパッケージ化されたIDE(Emacs + SLIME)、Common Lisp環境(Clozure Common Lisp)、ライブラリマネージャ(Quicklisp)です。 "Lisp in a Box"の後継です。実用的なCommon Lispの本でお勧めします。
  • あらかじめパックされていませんが、 SLIMEはEmacsをCommon Lisp IDEに変え、 使い始める手助けをするユーザマニュアルを持っています 。個別のCommon Lisp実装が必要です。

Common Lispの実装

このセクションでは、いくつかの一般的なCL実装とそのマニュアルを示します。特記のない限り、これらはフリーソフトウェアの実装です。 ClikiのフリーソフトウェアCommon Lisp実装 のリスト 、およびWikipediaの商用Common Lisp実装 のリストも参照してください。

こんにちは世界

以下は、Common LispとのREPLセッションからの抜粋であり、 "Hello、World!"関数が定義されて実行されます。 REPLの詳細な説明については、このページの下部にある注釈を参照してください。

CL-USER> (defun hello ()
           (format t "Hello, World!~%"))
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> 
 

これはhello という名前のゼロ引数の "関数"を定義し、 " "Hello, World!" という文字列を書き込み"Hello, World!" 標準出力に改行が続き、 NIL を返します。

書き込む関数を定義するには

(defun name (parameters...)
  code...)
 

この場合、関数はhello と呼ばれ、パラメータは使用されず、実行されるコードは1つの関数呼び出しを実行することです。 lisp関数から返される値は、実行する関数の最後のビットですhello は何らかの(format t "Hello, World!~%") 返します。

関数を呼び出すためのlispでは、write (function-name arguments...)function-namefunction-name で、 arguments... は呼び出しの引数の(スペースで区切られた)リストです。関数呼び出しのように見える特殊なケースがいくつかありますが、例えば上のコードではdefun 関数が呼び出されず、特殊な扱いを受け、代わりに関数を定義しています。

REPLの2番目のプロンプトでは、 hello 関数を定義した後、それを書いて(hello) パラメータなしで呼び出します。これは、パラメータt"Hello, World!~%" format 関数を呼び出します。 format 関数は与えられた引数に基づいてフォーマットされた出力を生成しformat (Cのprintf 高度なバージョンのようなものです)。最初の引数は、どこに出力するかを、 t は標準出力を意味します。 2番目の引数は何を印刷するか(および余分なパラメータをどのように解釈するか)を指示します。ディレクティブ(2番目の引数の特殊コード) ~% は、改行を出力するようにformatに指示します(つまり、UNIXの場合は\n 、Windowsの場合は\r\n )。通常、フォーマットはNIL (他の言語ではNULL ようなビット)をNULL

2番目のプロンプトの後、 Hello, World が出力され、次の行に戻り値がNIL ことがNIL ます。

こんにちは、名前

これはもう少し高度な例であり、一般的なlispのいくつかの機能を示しています。簡単なHello, World! から始めましょHello, World! REPLでインタラクティブな開発を実証しています。セミコロンからの任意のテキスト; 、行の残りの部分はコメントです。

CL-USER> (defun hello ()
       (format t "Hello, World!~%")) ;We start as before
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (defun hello-name (name) ;A function to say hello to anyone
       (format t "Hello, ~a~%" name)) ;~a prints the next argument to format
HELLO-NAME
CL-USER> (hello-name "Jack")
Hello, Jack
NIL
CL-USER> (hello-name "jack") ;doesn't capitalise names
Hello, jack
NIL
CL-USER> (defun hello-name (name) ;format has a feature to convert to title case
       (format t "Hello, ~:(~a~)~%" name)) ;anything between ~:( and ~) gets it
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack")
Hello, Jack
NIL
CL-USER> (defun hello-name (name)
       (format t "Hello, ~:(~a~)!~%" name))
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello-name "jack") ;now this works
Hello, Jack!
NIL
CL-USER> (defun hello (&optional (name "world")) ;we can take an optional argument
       (hello-name name)) ;name defaults to "world"
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (hello)
Hello, World!
NIL
CL-USER> (hello "jack")
Hello, Jack!
NIL
CL-USER> (hello "john doe") ;note that this capitalises both names
Hello, John Doe!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~a ~r" name number)) ;~r prints a number in English
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;this doesn't quite work
Hello, Louis sixteen
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a ~:r~)!" name number)) ;~:r prints an ordinal
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Sixteenth!
NIL
CL-USER> (defun hello-person (name &key (number))
       (format t "Hello, ~:(~a ~@r~)!" name number)) ;~@r prints Roman numerals
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16)
Hello, Louis Xvi!
NIL
CL-USER> (defun hello-person (name &key (number)) ;capitalisation was wrong
       (format t "Hello, ~:(~a~) ~:@r!" name number))
WARNING: redefining COMMON-LISP-USER::HELLO-PERSON in DEFUN
HELLO-PERSON
CL-USER> (hello-person "Louis" :number 16) ;thats better
Hello, Louis XVI!
NIL
CL-USER> (hello-person "Louis") ;we get an error because NIL is not a number
Hello, Louis ; Evaluation aborted on #<SB-FORMAT:FORMAT-ERROR {1006641AB3}>.
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 "")) ; here we define a variable called number
         (title (if title 
                (format nil "~:(~a~) " title)
                ""))) ; and here one called title
         (format nil "~a~:(~a~)~a" title name number))) ;we use them here

SAY-PERSON
CL-USER> (say-person "John") ;some examples
"John"
CL-USER> (say-person "john doe")
"John Doe"
CL-USER> (say-person "john doe" :number "JR")
"John Doe Jr"
CL-USER> (say-person "john doe" :number "Junior")
"John Doe Junior"
CL-USER> (say-person "john doe" :number 1)
"John Doe I"
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;this is wrong
"John Doe First"
CL-USER> (defun say-person (name &key (number 1 number-p)
                                      (title nil) (roman-number t))
       (let ((number (if number-p
                 (typecase number
                   (integer
                (format nil (if roman-number " ~:@r" " the ~:(~:r~)") number))
                   (otherwise
                (format nil " ~:(~a~)" number)))
                 ""))
         (title (if title 
                (format nil "~:(~a~) " title)
                "")))
         (format nil "~a~:(~a~)~a" title name number)))
WARNING: redefining COMMON-LISP-USER::SAY-PERSON in DEFUN
SAY-PERSON
CL-USER> (say-person "john doe" :number 1 :roman-number nil) ;thats better
"John Doe the First"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number nil)
"King Louis the Sixteenth"
CL-USER> (say-person "louis" :title "king" :number 16 :roman-number t)
"King Louis XVI"
CL-USER> (defun hello (&optional (name "World") &rest arguments) ;now we will just
       (apply #'hello-name name arguments)) ;pass all arguments to hello-name
WARNING: redefining COMMON-LISP-USER::HELLO in DEFUN
HELLO
CL-USER> (defun hello-name (name &rest arguments) ;which will now just use
       (format t "Hello, ~a!" (apply #'say-person name arguments))) ;say-person
WARNING: redefining COMMON-LISP-USER::HELLO-NAME in DEFUN
HELLO-NAME
CL-USER> (hello "louis" :title "king" :number 16) ;this works now
Hello, King Louis XVI!
NIL
CL-USER>
 

これは、Common Lispのformat 関数の高度な機能の一部と、オプションのパラメータやキーワード引数(例:number )などのいくつかの機能を強調しています。これはまた、共通のリスプでREPLでインタラクティブな開発の例を示しています。

ラムダ式と無名関数

無名関数は、 ラムダ式で名前なしで定義することができます。これらのタイプの関数を定義するには、キーワードdefun 代わりにキーワードlambda が使用されます。次の行はすべて同等であり、2つの数値の合計を出力する無名関数を定義します。

(lambda (x y) (+ x y))
(function (lambda (x y) (+ x y)))
#'(lambda (x y) (+ x y))
 

それらの有用性は、 ラムダフォームを作成する際に顕著です。つまり、最初の要素がラムダ式であり、残りの要素が無名関数の引数である形式のフォームです 。例( オンライン実行 ):

(print ((lambda (x y) (+ x y)) 1 2)) ; >> 3

(print (mapcar (lambda (x y) (+ x y)) '(1 2 3) '(2 -5 0))) ; >> (3 -3 3)
 

整数のリストの合計

(defun sum-list-integers (list)
    (reduce '+ list))

; 10
(sum-list-integers '(1 2 3 4))

; 55
(sum-list-integers '(1 2 3 4 5 6 7 8 9 10))
 

REPLの簡単なHello Worldプログラム

Common Lisp REPLはインタラクティブな環境です。プロンプト後に書かれたすべてのフォームが評価され、その値は評価の結果として後で印刷されます。ですから、Common Lispの最も簡単な "Hello、World!"プログラムは次のとおりです:

CL-USER> "Hello, World!"
"Hello, World!"
CL-USER>
 

ここで起こるのは、REPLへの入力で文字列コストが与えられ、評価され、結果が出力されることです。この例から分かるように、数字のような文字列、 NILT などの特殊記号やその他のリテラルは、 自己評価型です。つまり、それは自分自身に評価されます。