Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-07-10

サンプルコードによるLOOPマクロ入門 (9)

| 19:54 | サンプルコードによるLOOPマクロ入門 (9) - わだばLisperになる を含むブックマーク はてなブックマーク - サンプルコードによるLOOPマクロ入門 (9) - わだばLisperになる

繰り返し途中での脱出等

繰り返しの中で脱出したい場合は、良くあります。

この場合、(return)や使える場所では:returnを使用して繰り返しから抜けることができます。

これら以外にも脱出の常套句的なものが用意されています。

  • :while

次の式の値がNILの場合即座にLOOPを終了させます

集積の結果や、:finally節は実行されます。

(loop :as i :upfrom 0 :while (< i 10)
      :collect i)
;=> (0 1 2 3 4 5 6 7 8 9)
  • :until

次の式の値が非NILの場合即座にLOOPを終了させます。

集積の結果や、:finally節は実行されます。

(loop :as i :upfrom 0 :until (>= i 10)
      :collect i)
;=> (0 1 2 3 4 5 6 7 8 9)

以上、2つは、脱出というよりは、LOOPの終了条件といった感じです。

  • :always

次の式の値がNILの場合即座にLOOPから抜けます。脱出した場合のLOOPの返り値は、NILですが、途中脱出しなかった場合は、Tになります。

集積の結果や、:finally節は実行されません。

(defun list= (x y)
  (loop :for xx :in x
        :for yy :in y
        :always (eql xx yy)))

(list= '(1 2 3 4) '(1 2 3 4))
;=> T
  • :never

次の式の値が非NILの場合即座にLOOPから抜けます。脱出した場合のLOOPの返り値は、NILですが、途中脱出しなかった場合は、Tになります。

集積の結果や、:finally節は実行されません。

(loop :never 1)
;=> NIL
  • :thereis

次の式の値が非NILの場合即座にLOOPから抜けます。脱出した場合のLOOPの返り値は、式の値ですが、途中脱出しなかった場合は、NILになります。

集積の結果や、:finally節は実行されません。

(loop :thereis 1)
;=> 1

その他

CLでは、someや、every等がありますが、CL以前のMacLISPには存在しないということもあり、

(if (some #'oddp '(1 2 3 4))
    'foo
    'bar)
;=> FOO

(if (loop :for x :in '(1 2 3 4) :thereis (oddp x))
    'foo
    'bar)
;=> FOO

と書いたような例がちらほらあります。

サンプルコードによるLOOPマクロ入門 (8)

| 18:27 | サンプルコードによるLOOPマクロ入門 (8) - わだばLisperになる を含むブックマーク はてなブックマーク - サンプルコードによるLOOPマクロ入門 (8) - わだばLisperになる

for/as色々

全く計画性もなく書いてるので話題が前後してしまいますが、値を生成する:for節は色々な書き方ができます。

また、:forは別名で:asとも書けます。

初期値〜更新

DOマクロのように初期化〜更新を組で書くことができます。

この場合、:=と、:thenを組で使用します。

(loop :as i := 0 :then (1+ i)
      :repeat 10            ;これがないと止まりません。
      :collect i)
;=> (0 1 2 3 4 5 6 7 8 9)

更新部分と初期化部分が同じ場合、更新部分を省略できます。

(loop :for i := 0       ;毎度0が代入される
      :repeat 10
      :collect i 
      :do (setq i nil)) ;iをnilに変更して邪魔をする。
;=> (0 0 0 0 0 0 0 0 0 0)

サンプルコードによるLOOPマクロ入門 (7)

| 14:22 | サンプルコードによるLOOPマクロ入門 (7) - わだばLisperになる を含むブックマーク はてなブックマーク - サンプルコードによるLOOPマクロ入門 (7) - わだばLisperになる

値の収集 その2

:collectや、:sum等で値を収集する場合、一つだけでなく複数に分散して値を格納したい時があります。

そういう時には、:collect等の後に:intoを付け変数名を指定します。

注意点としては、:intoを指定しない場合は暗黙の収集変数に値が格納され、LOOPを抜けたときにその値がLOOPの結果の値とされますが、:intoで指定した場合は、手動で値を返してやらないといけません。この場合、:finally節で指定するのが一般的なようです。また、:into以下の変数は:into節により適切に初期化されるので、手動で初期化する必要はありません。

(loop :for i :upfrom 0 :upto 10
      :collect i :into all
      :when (oddp i)
        :collect i :into odds
      :else
        :collect i :into evens
      :end
      :sum i :into sum
      :maximize i :into max
      :minimize i :into min
      :finally (return `(all => ,all odds => ,odds evens => ,evens sum => ,sum max => ,max min => ,min)))
;=>
(ALL => (0 1 2 3 4 5 6 7 8 9 10)
 ODDS => (1 3 5 7 9)
 EVENS => (0 2 4 6 8 10)
 SUM => 55
 MAX => 10
 MIN => 0)

はまりどころ

  • finallyで(return)を忘れる
(loop :for i :from 0 :to 10 :collect i :into ans
      :finally ans)
  • せっかく丁寧に収集用の変数を宣言してあげたのに怒られる
(loop :with ans := ()
      :for i :from 0 :to 10 :collect i :into ans
      :finally (return ans))
;>>> Variable ANS in INTO clause is a duplicate

ゲスト



トラックバック - http://cadr.g.hatena.ne.jp/g000001/20080710