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 |

2010-10-23

Perl6の>><<演算子を真似てみる

| 20:21 | Perl6の>><<演算子を真似てみる - わだばLisperになる を含むブックマーク はてなブックマーク - Perl6の>><<演算子を真似てみる - わだばLisperになる

を読んでPerl6では、

(1, 2, 3) >>+<< (10, 20, 30);
#⇒ 11 22 33

みたいなことができることを知りました。

これは見た目は謎ですが、MAPのことだろうということで、早速真似して作ってみました。

(defmacro >> (fn << &rest lists)
  (declare (ignore <<))
  `(mapcar #',fn ,@lists))

<<をQUOTEしないで書きたかったのでマクロで。

これで、

(>> + <<
    '(1 2 3 4)
    '(2 3 4 5)
    '(3 4 5 6))
;⇒ (6 9 12 15)

(>> list <<
    '(1 2 3 4)
    '(2 3 4 5)
    '(3 4 5 6))
;⇒ ((1 1 2) (2 2 3) (3 3 4) (4 4 5))

(>> = <<
    '(1 2 3 4)
    '(2 3 4 5)
    '(3 4 5 6))
;⇒ (NIL NIL NIL NIL)

(>> /= <<
    '(1 2 3 4)
    '(2 3 4 5)
    '(3 4 5 6))
;⇒ (T T T T)

みたいに書けます。

マクロなのでAPPLY #'MAP〜みたいなことができないこともあり、悔しいので意味なく関数だけでなくマクロやスペシャルフォームでも使えるようにしてみます。

(defmacro >> (fn << &rest lists)
  (declare (ignore <<))
  (if (or (special-operator-p fn)
          (macro-function fn))
      (let ((gs (mapcar (lambda (x)
                          (declare (ignore x))
                          (gensym))
                        lists)))
        `(mapcar (lambda (,@gs) (,fn ,@gs))
                 ,@lists))
      `(mapcar #',fn ,@lists)))

動作

(>> and <<
    '(1 2 3 4)
    '(nil 3 4 5)
    '(3 4 5 6))
;⇒ (nil 4 5 6)

しかし、

(>> let <<
    '(((x 1) (y 2) (z 3)))
    '((print x))
    '((print y))
    '((print z)))

のようなものには対応してません…。

また、上記の定義だと>>と<<の間に空白が必要なのですが、>>foo<<と書けるようにするには、ややこしいことをする必要があります(リーダーマクロなど)

(>>and<<
   '(1 2 3 4)
   '(nil 3 4 5)
   '(3 4 5 6))

でも、そんなに見た目も変らないだろうということで放置。