2016-07-15 5 views
1

はじめに:私は現在、LISPで教えられていると思われる凝縮コースを取っています。私はLISPで一生働いたことがないので、週末。私は深刻なコードについて事前に謝罪します。私は、LISPの構文を使ってコードを動作させるだけで十分です。Common LISP(SBCL):ループ内の値を返す

私は現在、地図の色の問題を解決するプログラムに取り組んでいます。このコードは、各サブシーケンスの最初の要素が状態であり、2番目の要素が色を表すシーケンスをとります。 (制約リストによって定義される)状態と同じ色を持つ状態がないことを確認するためにチェックする。おそらくこれを行うにはもっとクリーンでシンプルな方法がたくさんあると思いますが、私が現在苦労しているのは、if文が満たされるたびに、dolistループに値Tが返されることです。これまで私は単純に値を返す関数を得ることができず、変数をtrueに設定してコードを動作させるためにループが終了するのを待っている、この醜い/間違った方法に頼らざるを得ませんでした。私はリターンを使用して、if文の中にTを持たせようとしましたが、どちらの場合もループは値を返すのではなく終了し、理由はわかりません。

(setq constraint '((A (B C E)) (B (A E F)) (C (A E F)) (D (F)) (E (A B C F)) (F (B C D E)))) 

(defun check_constraint (f s) 
    (setf ans nil) 
    (dolist (state constraint) 
     (if (eq (first state) f) 
      (if (search (list s) (second state)) 
       (setf ans T) ;;where I want it to just return T 
      ) 
     ) 
    ) 
    ans 
) 

;;ex: ((A R) (B R) (C B) (D R) (E B) (F G)) 
(defun check_conflict (lst) 
    (setf anb nil) 
    (dolist (state lst) 
     (dolist (neighbor (remove state lst)) 
      (if (check_constraint (first state) (first neighbor)) 
       (if (eq (second state) (second neighbor)) 
        (setf anb T)) ;;where I want it to just return T 
      ) 
     ) 
    ) 
    anb 
) 

編集:私は再帰でこれを修正しました。コードは今よりクリーンですが、私はまだ私の問題が何であるか知りたいです。これは再帰的なコードです。

(setq constraint '((A (B C E)) (B (A E F)) (C (A E F)) (D (F)) (E (A B C F)) (F (B C D E)))) 

(defun check_constraint (lst f s) 
    (COND 
     ((null lst) nil) 
     ((search (list (car (car lst))) f) 
      (if (search s (second (car lst))) T)) 
     (t (check_constraint (cdr lst) f s)) 
    ) 
) 

(defun check_neighbor (check lst) 
    (COND 
     ((null lst) nil) 
     ((check_constraint constraint (list (car check)) (list (first (first lst)))) 
      (if (eq (second check) (second (car lst))) T)) 
     (t (check_neighbor check (cdr lst))) 
    ) 
) 

;;(check_state '((A R) (B R) (C B) (D R) (E B) (F G))) 
(defun check_state (lst) 
    (COND 
     ((null lst) nil) 
     ((check_neighbor (car lst) (cdr lst)) T) 
     (t (check_state (cdr lst))) 
    ) 
) 
+0

多くのLisp方言がありますが、あなたはそのことを言いません。ほとんどの方言では、いくつかのより高いレベルのフォームから値を返すために使用することができる特殊な形式 'return'あります。残念ながら、それが適用される形式は、方言間で異なるものの1つです。その時点で '(return T)'を使うことは、私が知っている方言のほとんどで動作するでしょう。そして、あなたは '' ans''と '' anb''を使い捨てて、ループの後に '' NIL''を置くことができます。 – MAP

+0

@MAPそれは普通のリスプだし、それを試みて、私はそれをSBCLで動作させることができませんでした。 – Metasyntactic

答えて

4

最初にいくつかのスタイルの問題がありました。グローバル変数を宣言するには、DEFVAR or DEFPARAMETERを使用する必要があります。彼らはまた、彼らがグローバル(または実際に特別な)であることを示すために名前の周りにアスタリスクを持つべきです。

(defparameter *constraint* 
    '((A (B C E)) 
    (B (A E F)) 
    (C (A E F)) 
    (D (F)) 
    (E (A B C F)) 
    (F (B C D E)))) 

ものに名前を付けるためのlispの規則は、言葉(CHECK-CONSTRAINT代わりのCHECK_CONSTRAINT)との間にダッシュを使用することです。また、変数名の代わりに、略語(代わりにLSTLIST)のための完全な言葉を好む必要があります。閉じ括弧は、自分の行に書くべきではありません。

実際の問題です。 RETURNを使用して、NILという名前のブロックから値を返すことができます。あなたはそれだけで、その後分岐があるときWHENの代わりIFを使用することをお勧めします

(defun check-constraint (first second) 
    (dolist (state *constraint*) 
    (when (and (eq first (first state)) 
       (member second (second state))) 
     (return t)))) 

のような最初の関数を書くことができますので、ループは、そのようなブロックを確立します。私はまた、ANDを使用して一つに2つのIF Sを組み合わせました。あなたがSEARCHを使用するためのリストでSをラップしているので、私はあなたがおそらく(私は正確にコードが行うことになっているのか分からないのでわからないが)の代わりにMEMBERを使用したい考え出しました。あなたが間違っている場合は、それを変更することができます。

あなたはおそらくも、あなたが二つのループを持つ第二の機能では

(defun check-constraint (first second) 
    (member second (second (find first *constraint* :key #'first)))) 

にそれを簡素化することができます。あなたは内側の1から復帰するRETURNを使用する場合は、あなただけの外側のループを継続し、戻り値を無視してしまいます。したがって、内部ループの代わりに関数から戻るには、RETURN-FROMを使用する必要があります。

(defun check-conflict (list) 
    (dolist (state list) 
    (dolist (neighbor (remove state list)) 
     (when (and (check-constraint (first state) (first neighbor)) 
       (eq (second state) (second neighbor))) 
     (return-from check-conflict t))))) 
+0

これは完璧です!スタイルの問題のいくつかを私に歩いてもらう時間をとってくれてありがとう。私はできるだけ早くこれを選ぶことを急いでおり、コースのリソースは少し限られています。これは非常に有益でした。 – Metasyntactic

関連する問題