8

このコードは本からのものです:「LandOfLisp」最初のバージョンは本からのものです。読んでみると、2行目の「at-loc-p」の直前に「(」、3行目のlocの直後に「)」という括弧があると思いました。

(defun person-at (loc pers per-locs)
       (labels ((at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc)))
         (remove-if-not #'at-loc-p pers)))

しかし、これをテストすると、

(defun person-at (loc pers per-locs)
       (labels (at-loc-p (pers)
                 (eq (cadr (assoc pers per-locs)) loc))
         (remove-if-not #'at-loc-p pers)))

出てきた:

AT-LOC-Pの必須引数がラムダリスト(CCL :: FUNCNAME CCL :: LAMBDA-LIST&BODY CCL :: LABELS-FUNCTION-BODY)と一致しません。
[タイプCCL::SIMPLE-PROGRAM-ERRORの条件]

私は静かに理解していません。助けが必要。ありがとうございました。

4

6 に答える 6

11

LABELSで_

(defun person-at (loc pers per-locs)
  (labels ((at-loc-p (pers)
             (eq (cadr (assoc pers per-locs)) loc)))
    (remove-if-not #'at-loc-p pers)))

は構文labels ((function-name lambda-list [[local-declaration* | local-documentation]] local-form*)*) declaration* form*を持っているので、それが機能するためにはローカル関数定義のリストを提供する必要があります。

これらのローカル関数定義自体は括弧で囲まれているためlabels、この構造体のリストを渡す必要があります((fun1 (...) ...) (fun2 (...) ...) ...)

残念ながら、スタックトレースとエラーメッセージは、ここでエラーを見つけるのにあまり役立ちません。メッセージは、問題がにあることを示しておらずlabels、トレースの最上位にもないためです。4: (CCL::NX1-LABELS ...ヒントになります(ローカルマシンのデバッガーバッファ)。

labels詳細については、Hyperspecののドキュメントを参照してください。

于 2011-05-08T02:20:57.527 に答える
7

Lispではなく他の言語では、括弧は通常、演算子をグループ化するために使用されるため、多くの場合オプションです。しかし、Lispでは括弧は常に意味があります。追加またはオプションの括弧はない場合があります。

ほとんどの場合、式の前後の括弧は関数またはマクロアプリケーションを意味します。

(foo 1)

このような場合、式の開始時に2つの括弧が発生する可能性があります。たとえば、式の最初の要素が別の式である場合、それは関数自体に評価されます。たとえば、数値を取り、部分的に加算が適用された別の関数を返す関数を想像してみてください(ところで、これはカリーmake-adder化の例です)。

(defun make-adder (number)
   (lambda (another-number) (+ number another-number)))

この方法で関数変数を作成しincrement、それを変数に適用できます。

(defvar increment (make-adder 1))
(increment 5)                      ; ==> 6

しかし、直接呼び出すこともできます(これは、Common Lispでは機能しませんが、「Lisp-1」と呼ばれる他のLispでも同じ構文が機能するため、ここで言及する価値があると思います):

((make-adder 1) 5)                 ; ==> 6

最初に二重括弧を作ります。そしてもちろん、両方の括弧は必須です。

そして、あなたの状況を説明する最後のケースは、言語またはユーザーマクロがその目的のためにリストのリストを使用する場合です(Lispプログラム自体が式のリストのリストであることを今でも覚えていますか?)。たとえばdefun、最初の引数はシンボルである必要があり、2番目の引数はリストである必要があることを知っています。そしてlabelsマクロは、その最初の引数が定義のリストでなければならず、それぞれがリスト自体であることを知っています。これは、ユーザーが一度に複数のラベルを定義できるようにするために作成されました。

(labels ((definition-1) (definition-2) ...) 
   (do-this) (do-that) ...)

つまり、各括弧は何かを意味し、自分で削除することはできないことがわかります。

于 2011-05-08T02:54:58.247 に答える
3

かっこ「(」は不要だと思いました

そうですね。asdklfjhsbfかっこを好きなように追加および削除して、たとえば、記号の代わりに使用して機能することを期待できる以上に機能することを期待することはできませんdefun。LABELSを指定する必要が((function-name lambda-list forms) ... )あります。これは、LABELSの構文にすぎません。これに従わない場合、コンパイラはエラーを発生させます。

于 2011-05-08T02:17:43.297 に答える
2

実際、Lispにはパンテシスが一種の「不自然」な場所がいくつかあります。通常、ルールは非常に一貫しています。括弧はリストを開始し、リストの最初の要素は、残りのすべてのリスト要素をパラメーターとして使用する関数です。この一貫性はほとんどのマクロと特殊な形式でも維持され、これによりLispコードは非常に均一になります...ただし、一部のマクロと特殊な演算子の括弧は異なる意味を持ち、グループ化に使用されます...たとえば

(dolist (x L) (print x))

この場合、たとえばx最初のパンテシスでは、L引数として渡すと呼ばれる関数ではありません。別の例は

(let ((x 10)
      (y 20))
   (print (+ x y)))

この場合、括弧はグループ化のためだけに使用され、最初の要素(x 10)は明らかに適用される関数ではなく、その最初の要素もx関数ではありません。

labelsまったく同じようletに機能し、1つの関数がさらに定義されている場合に備えて、グループ化には明らかに「余分な」括弧が必要です。

これらの特殊なケースは確かにやや厄介ですが、それらは非常に少なく、Lispコードをいくらか記述した後、それらを内部化して、考えずに正しく処理することができます。

それらは、たとえば、正しいコードウォーカーを書くのを非常に難しくする非対称性でもあります。また、Lispのこの「構文領域」で間違いを犯した場合、残念ながら、エラーメッセージはエラーを示すのにあまり役立ちません。

もちろん、この「複雑さ」は他の言語と比較して何もありません(そして、C ++テンプレートを間違えたときのメッセージがどれほど明確であるかについては議論を始めましょう;-))。

Lisp構文が「取るに足らない」、あるいは単に存在しないということは完全には真実ではないと思います。Lisp構文は、文字レベルではなくLispフォームレベルでも存在し、少数の特殊なフォームとマクロを除いて、ほとんど簡単です。

于 2011-05-08T06:38:14.183 に答える
2

Lispでは括弧は重要で不可欠です。これで、 Land ofLispのミュージックビデオに次のように書かれていることがわかります。「朝食には括弧を食べます。プログラムが完了していない場合は、昼食に括弧を食べます。それはあなたのプログラムにたくさんの簡潔さとパンチを与えます。すぐにあなたもそれらについて夢を見るでしょう!

于 2011-05-08T19:57:39.037 に答える
1

@danleiが言ったように、//の最初の部分に関数定義のリストがなければなりませ。それが単一の要素である場合、それらの冗長に見える二重括弧で終わります。 letlabelsflet

于 2011-05-08T02:30:09.510 に答える