1

if数か月前に、多くのステートメントを含むコードをプログラミングしました。もしregion-active-p、もしbeginning-of-line、そういうこと。

Lispについて学んだのでcond、自分のコードを大幅に改善できないかと考えていました。

問題は、cond私が見る限り、これは「真」の場合にのみ動作していることですが、実際にback-to-indentationはこれらのチェックの間に移動する必要があります。

最後の句を適切にスキップするには、変数値を設定する必要さえあります。

(defun uncomment-mode-specific ()  
  "Uncomment region OR uncomment beginning of line comment OR uncomment end"
  (interactive)
  (let ((scvar 0) (scskipvar 0))
    (save-excursion
      (if (region-active-p)
         (progn (uncomment-region (region-beginning) (region-end))
         (setq scskipvar 1))
        (back-to-indentation))   ; this is that "else" part that doesn't fit in cond

      (while (string= (byte-to-string (following-char)) comment-start) 
       (delete-char 1) 
       (setq scskipvar 1))
      (indent-for-tab-command)

      (when (= scskipvar 0)
         (search-forward comment-start nil t)
         (backward-char 1)
         (kill-line))
    )))
)

したがって、基本的に私の質問は、別の節のチェックの前に、節に「真」を与えないことの結果をもたらしたいということです。これは可能ですか?そうでない場合、何をするのが最善でしょうか?

編集:これを解決策の例として使用しているので、理解しやすいように書き留めました。

リージョンがアクティブな場合、リージョンからコメントを削除します。そうでない場合は、ポイントを意図に移動します。

次の文字がコメント文字である限り、削除します。その後、この行をインデントします。

上記のいずれも行わなかった場合は、前方にコメント文字を検索し、その行を削除します。

4

4 に答える 4

4
(defmacro fcond (&rest body)
  (labels ((%substitute-last-or-fail 
            (new old seq)
            (loop for elt on seq
                  nconc
                  (if (eql (car elt) old)
                      (when (cdr elt)
                        (error "`%S' must be the last experssion in the clause" 
                               (car elt)))
                    (list new)
                    (list (car elt))))))
    (loop with matched = (gensym)
          with catcher = (gensym)
          for (head . rest) in body
          collect
          `(when (or ,head ,matched)
             (setq ,matched t)
             ,@(%substitute-last-or-fail `(throw ',catcher nil) 'return rest))
          into clauses
          finally
          (return `(let (,matched) (catch ',catcher ,@clauses))))))

(macroexpand '(fcond
               ((= 1 2) (message "1 = 2"))
               ((= 1 1) (message "1 = 1"))
               ((= 1 3) (message "1 = 3") return)
               ((= 1 4) (message "1 = 4"))))
(let (G36434)
  (catch (quote G36435)
    (when (or (= 1 2) G36434)
      (setq G36434 t)
      (message "1 = 2"))
    (when (or (= 1 1) G36434)
      (setq G36434 t)
      (message "1 = 1"))
    (when (or (= 1 3) G36434)
      (setq G36434 t)
      (message "1 = 3")
      (throw (quote G36435) nil))
    (when (or (= 1 4) G36434)
      (setq G36434 t)
      (message "1 = 4"))))

ここでは、すぐに実行できること、つまりswitch、Cの動作を模倣するものを求めていると思います。

returnアイデアは、すべての句が等しいかどうか順番にテストされ、1 つが一致する場合、キーワードまで、後続のすべての句が実行されるというものです (これは C になりますbreakが、Lisp はreturnループ内で同様の目的で使用するため、return良くなる)。したがって、上記のコードは次のように出力されます。

1 = 1
1 = 3

技術的には、これはswitchC では機能しませんが、同じ効果が得られます。

簡単にするためにここで行った 1 つのことは、避けたい/別の方法で解決したい -returnキーワードの使用です。おそらく、検索方法についてより厳密なルールを課したいと思うでしょう。

于 2013-01-03T10:14:17.187 に答える
4
(defun delete-on-this-line (regex)
  (replace-regexp regex "" nil (line-beginning-position) (line-end-position)))

(defun delete-leading-comment-chars ()
  (delete-on-this-line (eval `(rx bol (* space) (group (+ ,comment-start)))))) 

(defun delete-trailing-comment-chars ()
  (delete-on-this-line (eval `(rx (group (+ ,comment-end)) (* space) eol))))

(defun delete-trailing-comment ()
  (delete-on-this-line (eval `(rx (group (+ ,comment-start) (* anything) eol)))))

(defun uncomment-dwim ()
  (interactive)
  (save-excursion
    (if (region-active-p) 
        (uncomment-region (region-beginning) (region-end))
      (or (delete-leading-comment-chars) 
          (delete-trailing-comment-chars)
          (delete-trailing-comment)))))

編集:ちょっとした説明: ループを管理して削除を行うよりも、正規表現の置換を行う方がはるかに簡単であるため、状態が取り除かれます。また、手順はすべて相互に排他的であるためor、各オプションにのみ使用できます。

このrxマクロは、有効な正規表現にコンパイルされる小さな DSL であり、Lispy 構文変換にも適しているため、現在のモードのコメント文字を使用して動的に正規表現を構築できます。

于 2013-01-03T10:27:35.973 に答える
3

状態

Cond はリスト内の一連の条件を評価します。リスト内の各項目は条件であり、次に実行可能な命令です。

Emacs Lisp のマニュアルにある例は、それがどのように機能するかを示すのに十分です。ここでは、それがどのように機能するかを理解するのに役立つように注釈を付けました。

  (cond ((numberp x) x) ;; is x a number? return x
        ((stringp x) x) ;; is x a string? return x
        ((bufferp x) ;; is x a buffer? 
         (setq temporary-hack x) ;; set temporary-hack to buffer x
         (buffer-name x))        ;; return the buffer-name for buffer x
        ((symbolp x) (symbol-value x))) ;; is x a symbol? return the value of x

条件の各部分は好きなように評価できますが、x上記の事実は各条件で偶然です。

例えば:

 (cond ((eq 1 2) "Omg equality borked!") ;; Will never be true
       (t "default")) ;; always true

そのため、switch との比較は少し制限されています。これは基本的に、最初の true 条件の本体リストを実行/返す if ステートメントのリストです。

うまくいけば、これがconをよりよく理解するのに役立ちます。

 (cond (condition body ... ) ;; execute body of 1st passing  
       (condition body ... ) ;; condition and return result  
       (condition body ... ) ;; of the final evaluation.
       ;; etc
 )  

また

コードの構造によっては、OR を使用して switch と同様のことを行うことができます。

これは関数型スタイルではありません。これは、副作用に依存して目的を実行し、フロー制御のブール値を返すためです。疑似 Lisp の例を次に示します。

(また)

(or
     (lambda() (do something)
            (evaluate t or nil) ; nil to continue; t to quit.
     )
     (lambda() (do something)
            (evaluate t or nil) ; nil to continue; t to quit.
     )
     (lambda() (do something)
            (evaluate t or nil) ; nil to continue; t to quit.
     )
     (lambda() (do something)
            (evaluate t or nil) ; nil to continue; t to quit.
     )
)         

を使用したスイッチのような構造の実際の例を次に示しますor

(or
 (when (= 1 1) 
   (progn 
   (insert "hello\n")
           nil))
 (when (= 1 2)  ;; condition fails.
   (progn 
   (insert "hello\n")
           nil)) ;; returns false (nil)
 (when (= 1 1) 
   (progn 
   (insert "hello\n")
           t)) ;; returns true, so we bail.
 (when (= 1 1) 
   (progn 
   (insert "hello\n")
           nil))
)

インサート :

hello
hello

(と)

and 演算子 (Lisp だけでなく) も非常に便利です。true になるまですべてを評価する代わりに、false が評価されるまで true である条件を評価します。

または & と の両方を使用して、有用なロジック ツリーを構築できます。

于 2013-01-03T09:18:12.257 に答える
1

これは、それを別々の関数に分解すると簡単になるというクリスの考えに従って、私が今やった方法です。

or編集: Slomojoから得たこのスレッドで得た知識も適用しました(これ以上変数はありません!)

(defun sc-uncomment ()
  (interactive)
  (or 
   (if (region-active-p) 
     (uncomment-region (region-beginning) (region-end))
    (back-to-indentation)
    nil)
   (if (string= (byte-to-string (following-char)) comment-start)
     (sc-check-start)
    (sc-end))))

(defun sc-check-start ()
  (interactive)
  (while (string= (byte-to-string (following-char)) comment-start) 
    (delete-char 1)) 
)

(defun sc-end ()
  (interactive)
  (search-forward comment-start nil t)
  (backward-char 1)
  (kill-line))
)
于 2013-01-03T10:48:59.897 に答える